@@ -153,6 +153,43 @@ 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+ /// # Platform-specific behavior
162+ ///
163+ /// On supported systems (including Windows and some UNIX-based OSes), this function acquires a
164+ /// handle/file descriptor for the directory. This allows functions like [`Dir::open_file`] to
165+ /// avoid [TOCTOU] errors when the directory itself is being moved.
166+ ///
167+ /// On other systems, it stores an absolute path (see [`canonicalize()`]). In the latter case, no
168+ /// [TOCTOU] guarantees are made.
169+ ///
170+ /// # Examples
171+ ///
172+ /// Opens a directory and then a file inside it.
173+ ///
174+ /// ```no_run
175+ /// #![feature(dirfd)]
176+ /// use std::{fs::Dir, io};
177+ ///
178+ /// fn main() -> std::io::Result<()> {
179+ /// let dir = Dir::open("foo")?;
180+ /// let mut file = dir.open_file("bar.txt")?;
181+ /// let contents = io::read_to_string(file)?;
182+ /// assert_eq!(contents, "Hello, world!");
183+ /// Ok(())
184+ /// }
185+ /// ```
186+ ///
187+ /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
188+ #[ unstable( feature = "dirfd" , issue = "120426" ) ]
189+ pub struct Dir {
190+ inner : fs_imp:: Dir ,
191+ }
192+
156193/// Metadata information about a file.
157194///
158195/// This structure is returned from the [`metadata`] or
@@ -1474,6 +1511,87 @@ impl Seek for Arc<File> {
14741511 }
14751512}
14761513
1514+ impl Dir {
1515+ /// Attempts to open a directory at `path` in read-only mode.
1516+ ///
1517+ /// # Errors
1518+ ///
1519+ /// This function will return an error if `path` does not point to an existing directory.
1520+ /// Other errors may also be returned according to [`OpenOptions::open`].
1521+ ///
1522+ /// # Examples
1523+ ///
1524+ /// ```no_run
1525+ /// #![feature(dirfd)]
1526+ /// use std::{fs::Dir, io};
1527+ ///
1528+ /// fn main() -> std::io::Result<()> {
1529+ /// let dir = Dir::open("foo")?;
1530+ /// let mut f = dir.open_file("bar.txt")?;
1531+ /// let contents = io::read_to_string(f)?;
1532+ /// assert_eq!(contents, "Hello, world!");
1533+ /// Ok(())
1534+ /// }
1535+ /// ```
1536+ #[ unstable( feature = "dirfd" , issue = "120426" ) ]
1537+ pub fn open < P : AsRef < Path > > ( path : P ) -> io:: Result < Self > {
1538+ fs_imp:: Dir :: open ( path. as_ref ( ) , & OpenOptions :: new ( ) . read ( true ) . 0 )
1539+ . map ( |inner| Self { inner } )
1540+ }
1541+
1542+ /// Attempts to open a file in read-only mode relative to this directory.
1543+ ///
1544+ /// # Errors
1545+ ///
1546+ /// This function will return an error if `path` does not point to an existing file.
1547+ /// Other errors may also be returned according to [`OpenOptions::open`].
1548+ ///
1549+ /// # Examples
1550+ ///
1551+ /// ```no_run
1552+ /// #![feature(dirfd)]
1553+ /// use std::{fs::Dir, io};
1554+ ///
1555+ /// fn main() -> std::io::Result<()> {
1556+ /// let dir = Dir::open("foo")?;
1557+ /// let mut f = dir.open_file("bar.txt")?;
1558+ /// let contents = io::read_to_string(f)?;
1559+ /// assert_eq!(contents, "Hello, world!");
1560+ /// Ok(())
1561+ /// }
1562+ /// ```
1563+ #[ unstable( feature = "dirfd" , issue = "120426" ) ]
1564+ pub fn open_file < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < File > {
1565+ self . inner
1566+ . open_file ( path. as_ref ( ) , & OpenOptions :: new ( ) . read ( true ) . 0 )
1567+ . map ( |f| File { inner : f } )
1568+ }
1569+ }
1570+
1571+ impl AsInner < fs_imp:: Dir > for Dir {
1572+ #[ inline]
1573+ fn as_inner ( & self ) -> & fs_imp:: Dir {
1574+ & self . inner
1575+ }
1576+ }
1577+ impl FromInner < fs_imp:: Dir > for Dir {
1578+ fn from_inner ( f : fs_imp:: Dir ) -> Dir {
1579+ Dir { inner : f }
1580+ }
1581+ }
1582+ impl IntoInner < fs_imp:: Dir > for Dir {
1583+ fn into_inner ( self ) -> fs_imp:: Dir {
1584+ self . inner
1585+ }
1586+ }
1587+
1588+ #[ unstable( feature = "dirfd" , issue = "120426" ) ]
1589+ impl fmt:: Debug for Dir {
1590+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1591+ self . inner . fmt ( f)
1592+ }
1593+ }
1594+
14771595impl OpenOptions {
14781596 /// Creates a blank new set of options ready for configuration.
14791597 ///
0 commit comments