@@ -153,6 +153,43 @@ pub enum TryLockError {
153
153
WouldBlock ,
154
154
}
155
155
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
+
156
193
/// Metadata information about a file.
157
194
///
158
195
/// This structure is returned from the [`metadata`] or
@@ -1474,6 +1511,84 @@ impl Seek for Arc<File> {
1474
1511
}
1475
1512
}
1476
1513
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) . map ( |inner| Self { inner } )
1539
+ }
1540
+
1541
+ /// Attempts to open a file in read-only mode relative to this directory.
1542
+ ///
1543
+ /// # Errors
1544
+ ///
1545
+ /// This function will return an error if `path` does not point to an existing file.
1546
+ /// Other errors may also be returned according to [`OpenOptions::open`].
1547
+ ///
1548
+ /// # Examples
1549
+ ///
1550
+ /// ```no_run
1551
+ /// #![feature(dirfd)]
1552
+ /// use std::{fs::Dir, io};
1553
+ ///
1554
+ /// fn main() -> std::io::Result<()> {
1555
+ /// let dir = Dir::open("foo")?;
1556
+ /// let mut f = dir.open_file("bar.txt")?;
1557
+ /// let contents = io::read_to_string(f)?;
1558
+ /// assert_eq!(contents, "Hello, world!");
1559
+ /// Ok(())
1560
+ /// }
1561
+ /// ```
1562
+ #[ unstable( feature = "dirfd" , issue = "120426" ) ]
1563
+ pub fn open_file < P : AsRef < Path > > ( & self , path : P ) -> io:: Result < File > {
1564
+ self . inner . open_file ( path) . map ( |f| File { inner : f } )
1565
+ }
1566
+ }
1567
+
1568
+ impl AsInner < fs_imp:: Dir > for Dir {
1569
+ #[ inline]
1570
+ fn as_inner ( & self ) -> & fs_imp:: Dir {
1571
+ & self . inner
1572
+ }
1573
+ }
1574
+ impl FromInner < fs_imp:: Dir > for Dir {
1575
+ fn from_inner ( f : fs_imp:: Dir ) -> Dir {
1576
+ Dir { inner : f }
1577
+ }
1578
+ }
1579
+ impl IntoInner < fs_imp:: Dir > for Dir {
1580
+ fn into_inner ( self ) -> fs_imp:: Dir {
1581
+ self . inner
1582
+ }
1583
+ }
1584
+
1585
+ #[ unstable( feature = "dirfd" , issue = "120426" ) ]
1586
+ impl fmt:: Debug for Dir {
1587
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1588
+ self . inner . fmt ( f)
1589
+ }
1590
+ }
1591
+
1477
1592
impl OpenOptions {
1478
1593
/// Creates a blank new set of options ready for configuration.
1479
1594
///
0 commit comments