@@ -152,6 +152,43 @@ pub enum TryLockError {
152152 WouldBlock ,
153153}
154154
155+ /// An object providing access to a directory on the filesystem.
156+ ///
157+ /// Directories are automatically closed when they go out of scope. Errors detected
158+ /// on closing are ignored by the implementation of `Drop`.
159+ ///
160+ /// # Platform-specific behavior
161+ ///
162+ /// On supported systems (including Windows and some UNIX-based OSes), this function acquires a
163+ /// handle/file descriptor for the directory. This allows functions like [`Dir::open_file`] to
164+ /// avoid [TOCTOU] errors when the directory itself is being moved.
165+ ///
166+ /// On other systems, it stores an absolute path (see [`canonicalize()`]). In the latter case, no
167+ /// [TOCTOU] guarantees are made.
168+ ///
169+ /// # Examples
170+ ///
171+ /// Opens a directory and then a file inside it.
172+ ///
173+ /// ```no_run
174+ /// #![feature(dirfd)]
175+ /// use std::{fs::Dir, io};
176+ ///
177+ /// fn main() -> std::io::Result<()> {
178+ /// let dir = Dir::open("foo")?;
179+ /// let mut file = dir.open_file("bar.txt")?;
180+ /// let contents = io::read_to_string(file)?;
181+ /// assert_eq!(contents, "Hello, world!");
182+ /// Ok(())
183+ /// }
184+ /// ```
185+ ///
186+ /// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
187+ #[ unstable( feature = "dirfd" , issue = "120426" ) ]
188+ pub struct Dir {
189+ inner : fs_imp:: Dir ,
190+ }
191+
155192/// Metadata information about a file.
156193///
157194/// This structure is returned from the [`metadata`] or
@@ -1554,6 +1591,87 @@ impl Seek for Arc<File> {
15541591 }
15551592}
15561593
1594+ impl Dir {
1595+ /// Attempts to open a directory at `path` in read-only mode.
1596+ ///
1597+ /// # Errors
1598+ ///
1599+ /// This function will return an error if `path` does not point to an existing directory.
1600+ /// Other errors may also be returned according to [`OpenOptions::open`].
1601+ ///
1602+ /// # Examples
1603+ ///
1604+ /// ```no_run
1605+ /// #![feature(dirfd)]
1606+ /// use std::{fs::Dir, io};
1607+ ///
1608+ /// fn main() -> std::io::Result<()> {
1609+ /// let dir = Dir::open("foo")?;
1610+ /// let mut f = dir.open_file("bar.txt")?;
1611+ /// let contents = io::read_to_string(f)?;
1612+ /// assert_eq!(contents, "Hello, world!");
1613+ /// Ok(())
1614+ /// }
1615+ /// ```
1616+ #[ unstable( feature = "dirfd" , issue = "120426" ) ]
1617+ pub fn open < P : AsRef < Path > > ( path : P ) -> io:: Result < Self > {
1618+ fs_imp:: Dir :: open ( path. as_ref ( ) , & OpenOptions :: new ( ) . read ( true ) . 0 )
1619+ . map ( |inner| Self { inner } )
1620+ }
1621+
1622+ /// Attempts to open a file in read-only mode relative to this directory.
1623+ ///
1624+ /// # Errors
1625+ ///
1626+ /// This function will return an error if `path` does not point to an existing file.
1627+ /// Other errors may also be returned according to [`OpenOptions::open`].
1628+ ///
1629+ /// # Examples
1630+ ///
1631+ /// ```no_run
1632+ /// #![feature(dirfd)]
1633+ /// use std::{fs::Dir, io};
1634+ ///
1635+ /// fn main() -> std::io::Result<()> {
1636+ /// let dir = Dir::open("foo")?;
1637+ /// let mut f = dir.open_file("bar.txt")?;
1638+ /// let contents = io::read_to_string(f)?;
1639+ /// assert_eq!(contents, "Hello, world!");
1640+ /// Ok(())
1641+ /// }
1642+ /// ```
1643+ #[ unstable( feature = "dirfd" , issue = "120426" ) ]
1644+ pub fn open_file < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < File > {
1645+ self . inner
1646+ . open_file ( path. as_ref ( ) , & OpenOptions :: new ( ) . read ( true ) . 0 )
1647+ . map ( |f| File { inner : f } )
1648+ }
1649+ }
1650+
1651+ impl AsInner < fs_imp:: Dir > for Dir {
1652+ #[ inline]
1653+ fn as_inner ( & self ) -> & fs_imp:: Dir {
1654+ & self . inner
1655+ }
1656+ }
1657+ impl FromInner < fs_imp:: Dir > for Dir {
1658+ fn from_inner ( f : fs_imp:: Dir ) -> Dir {
1659+ Dir { inner : f }
1660+ }
1661+ }
1662+ impl IntoInner < fs_imp:: Dir > for Dir {
1663+ fn into_inner ( self ) -> fs_imp:: Dir {
1664+ self . inner
1665+ }
1666+ }
1667+
1668+ #[ unstable( feature = "dirfd" , issue = "120426" ) ]
1669+ impl fmt:: Debug for Dir {
1670+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1671+ self . inner . fmt ( f)
1672+ }
1673+ }
1674+
15571675impl OpenOptions {
15581676 /// Creates a blank new set of options ready for configuration.
15591677 ///
0 commit comments