@@ -34,6 +34,12 @@ use std::pin::Pin;
34
34
use std:: sync:: Arc ;
35
35
use std:: task:: { Context , Poll } ;
36
36
37
+ #[ cfg( unix) ]
38
+ use std:: os:: unix:: fs:: { DirEntryExt as _, OpenOptionsExt as _} ;
39
+
40
+ #[ cfg( windows) ]
41
+ use std:: os:: windows:: fs:: OpenOptionsExt as _;
42
+
37
43
use blocking:: { unblock, Unblock } ;
38
44
use futures_lite:: io:: { AsyncRead , AsyncSeek , AsyncWrite , AsyncWriteExt } ;
39
45
use futures_lite:: stream:: Stream ;
@@ -247,8 +253,7 @@ pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
247
253
///
248
254
/// let mut entries = async_fs::read_dir(".").await?;
249
255
///
250
- /// while let Some(res) = entries.next().await {
251
- /// let entry = res?;
256
+ /// while let Some(entry) = entries.try_next().await? {
252
257
/// println!("{}", entry.file_name().to_string_lossy());
253
258
/// }
254
259
/// # std::io::Result::Ok(()) });
@@ -326,8 +331,7 @@ impl DirEntry {
326
331
/// # futures_lite::future::block_on(async {
327
332
/// let mut dir = async_fs::read_dir(".").await?;
328
333
///
329
- /// while let Some(res) = dir.next().await {
330
- /// let entry = res?;
334
+ /// while let Some(entry) = dir.try_next().await? {
331
335
/// println!("{:?}", entry.path());
332
336
/// }
333
337
/// # std::io::Result::Ok(()) });
@@ -359,8 +363,7 @@ impl DirEntry {
359
363
/// # futures_lite::future::block_on(async {
360
364
/// let mut dir = async_fs::read_dir(".").await?;
361
365
///
362
- /// while let Some(res) = dir.next().await {
363
- /// let entry = res?;
366
+ /// while let Some(entry) = dir.try_next().await? {
364
367
/// println!("{:?}", entry.metadata().await?);
365
368
/// }
366
369
/// # std::io::Result::Ok(()) });
@@ -392,8 +395,7 @@ impl DirEntry {
392
395
/// # futures_lite::future::block_on(async {
393
396
/// let mut dir = async_fs::read_dir(".").await?;
394
397
///
395
- /// while let Some(res) = dir.next().await {
396
- /// let entry = res?;
398
+ /// while let Some(entry) = dir.try_next().await? {
397
399
/// println!("{:?}", entry.file_type().await?);
398
400
/// }
399
401
/// # std::io::Result::Ok(()) });
@@ -413,8 +415,7 @@ impl DirEntry {
413
415
/// # futures_lite::future::block_on(async {
414
416
/// let mut dir = async_fs::read_dir(".").await?;
415
417
///
416
- /// while let Some(res) = dir.next().await {
417
- /// let entry = res?;
418
+ /// while let Some(entry) = dir.try_next().await? {
418
419
/// println!("{}", entry.file_name().to_string_lossy());
419
420
/// }
420
421
/// # std::io::Result::Ok(()) });
@@ -437,7 +438,7 @@ impl Clone for DirEntry {
437
438
}
438
439
439
440
#[ cfg( unix) ]
440
- impl std :: os :: unix:: fs :: DirEntryExt for DirEntry {
441
+ impl unix:: DirEntryExt for DirEntry {
441
442
fn ino ( & self ) -> u64 {
442
443
self . 0 . ino ( )
443
444
}
@@ -764,7 +765,7 @@ impl DirBuilder {
764
765
}
765
766
766
767
#[ cfg( unix) ]
767
- impl std :: os :: unix:: fs :: DirBuilderExt for DirBuilder {
768
+ impl unix:: DirBuilderExt for DirBuilder {
768
769
fn mode ( & mut self , mode : u32 ) -> & mut Self {
769
770
self . mode = Some ( mode) ;
770
771
self
@@ -1428,7 +1429,7 @@ impl Default for OpenOptions {
1428
1429
}
1429
1430
1430
1431
#[ cfg( unix) ]
1431
- impl std :: os :: unix:: fs :: OpenOptionsExt for OpenOptions {
1432
+ impl unix:: OpenOptionsExt for OpenOptions {
1432
1433
fn mode ( & mut self , mode : u32 ) -> & mut Self {
1433
1434
self . 0 . mode ( mode) ;
1434
1435
self
@@ -1441,7 +1442,7 @@ impl std::os::unix::fs::OpenOptionsExt for OpenOptions {
1441
1442
}
1442
1443
1443
1444
#[ cfg( windows) ]
1444
- impl std :: os :: windows:: fs :: OpenOptionsExt for OpenOptions {
1445
+ impl windows:: OpenOptionsExt for OpenOptions {
1445
1446
fn access_mode ( & mut self , access : u32 ) -> & mut Self {
1446
1447
self . 0 . access_mode ( access) ;
1447
1448
self
@@ -1474,9 +1475,7 @@ pub mod unix {
1474
1475
use super :: * ;
1475
1476
1476
1477
#[ doc( no_inline) ]
1477
- pub use std:: os:: unix:: fs:: {
1478
- DirBuilderExt , DirEntryExt , FileTypeExt , MetadataExt , OpenOptionsExt , PermissionsExt ,
1479
- } ;
1478
+ pub use std:: os:: unix:: fs:: { FileTypeExt , MetadataExt , PermissionsExt } ;
1480
1479
1481
1480
/// Creates a new symbolic link on the filesystem.
1482
1481
///
@@ -1494,6 +1493,92 @@ pub mod unix {
1494
1493
let dst = dst. as_ref ( ) . to_owned ( ) ;
1495
1494
unblock ( move || std:: os:: unix:: fs:: symlink ( & src, & dst) ) . await
1496
1495
}
1496
+
1497
+ /// Unix-specific extensions to [`DirBuilder`].
1498
+ pub trait DirBuilderExt {
1499
+ /// Sets the mode to create new directories with.
1500
+ ///
1501
+ /// This option defaults to `0o777`.
1502
+ ///
1503
+ /// # Examples
1504
+ ///
1505
+ /// ```no_run
1506
+ /// use async_fs::{DirBuilder, unix::DirBuilderExt};
1507
+ ///
1508
+ /// let mut builder = DirBuilder::new();
1509
+ /// builder.mode(0o755);
1510
+ /// ```
1511
+ fn mode ( & mut self , mode : u32 ) -> & mut Self ;
1512
+ }
1513
+
1514
+ /// Unix-specific extension methods for [`DirEntry`].
1515
+ pub trait DirEntryExt {
1516
+ /// Returns the underlying `d_ino` field in the contained `dirent` structure.
1517
+ ///
1518
+ /// # Examples
1519
+ ///
1520
+ /// ```no_run
1521
+ /// use async_fs::unix::DirEntryExt;
1522
+ /// use futures_lite::stream::StreamExt;
1523
+ ///
1524
+ /// # futures_lite::future::block_on(async {
1525
+ /// let mut entries = async_fs::read_dir(".").await?;
1526
+ ///
1527
+ /// while let Some(entry) = entries.try_next().await? {
1528
+ /// println!("{:?}: {}", entry.file_name(), entry.ino());
1529
+ /// }
1530
+ /// # std::io::Result::Ok(()) });
1531
+ /// ```
1532
+ fn ino ( & self ) -> u64 ;
1533
+ }
1534
+
1535
+ /// Unix-specific extensions to [`OpenOptions`].
1536
+ pub trait OpenOptionsExt {
1537
+ /// Sets the mode bits that a new file will be created with.
1538
+ ///
1539
+ /// If a new file is created as part of an [`OpenOptions::open()`] call then this
1540
+ /// specified `mode` will be used as the permission bits for the new file.
1541
+ ///
1542
+ /// If no `mode` is set, the default of `0o666` will be used.
1543
+ /// The operating system masks out bits with the system's `umask`, to produce
1544
+ /// the final permissions.
1545
+ ///
1546
+ /// # Examples
1547
+ ///
1548
+ /// ```no_run
1549
+ /// use async_fs::{OpenOptions, unix::OpenOptionsExt};
1550
+ ///
1551
+ /// # futures_lite::future::block_on(async {
1552
+ /// let mut options = OpenOptions::new();
1553
+ /// // Read/write permissions for owner and read permissions for others.
1554
+ /// options.mode(0o644);
1555
+ /// let file = options.open("foo.txt").await?;
1556
+ /// # std::io::Result::Ok(()) });
1557
+ /// ```
1558
+ fn mode ( & mut self , mode : u32 ) -> & mut Self ;
1559
+
1560
+ /// Passes custom flags to the `flags` argument of `open`.
1561
+ ///
1562
+ /// The bits that define the access mode are masked out with `O_ACCMODE`, to
1563
+ /// ensure they do not interfere with the access mode set by Rust's options.
1564
+ ///
1565
+ /// Custom flags can only set flags, not remove flags set by Rust's options.
1566
+ /// This options overwrites any previously set custom flags.
1567
+ ///
1568
+ /// # Examples
1569
+ ///
1570
+ /// ```no_run
1571
+ /// use async_fs::{OpenOptions, unix::OpenOptionsExt};
1572
+ ///
1573
+ /// # futures_lite::future::block_on(async {
1574
+ /// let mut options = OpenOptions::new();
1575
+ /// options.write(true);
1576
+ /// options.custom_flags(libc::O_NOFOLLOW);
1577
+ /// let file = options.open("foo.txt").await?;
1578
+ /// # std::io::Result::Ok(()) });
1579
+ /// ```
1580
+ fn custom_flags ( & mut self , flags : i32 ) -> & mut Self ;
1581
+ }
1497
1582
}
1498
1583
1499
1584
/// Windows-specific extensions.
@@ -1502,7 +1587,7 @@ pub mod windows {
1502
1587
use super :: * ;
1503
1588
1504
1589
#[ doc( no_inline) ]
1505
- pub use std:: os:: windows:: fs:: { MetadataExt , OpenOptionsExt } ;
1590
+ pub use std:: os:: windows:: fs:: MetadataExt ;
1506
1591
1507
1592
/// Creates a new directory symbolic link on the filesystem.
1508
1593
///
@@ -1537,4 +1622,159 @@ pub mod windows {
1537
1622
let dst = dst. as_ref ( ) . to_owned ( ) ;
1538
1623
unblock ( move || std:: os:: windows:: fs:: symlink_file ( & src, & dst) ) . await
1539
1624
}
1625
+
1626
+ /// Windows-specific extensions to [`OpenOptions`].
1627
+ pub trait OpenOptionsExt {
1628
+ /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
1629
+ /// with the specified value.
1630
+ ///
1631
+ /// This will override the `read`, `write`, and `append` flags on the
1632
+ /// [`OpenOptions`] structure. This method provides fine-grained control over
1633
+ /// the permissions to read, write and append data, attributes (like hidden
1634
+ /// and system), and extended attributes.
1635
+ ///
1636
+ /// # Examples
1637
+ ///
1638
+ /// ```no_run
1639
+ /// use async_fs::{OpenOptions, windows::OpenOptionsExt};
1640
+ ///
1641
+ /// # futures_lite::future::block_on(async {
1642
+ /// // Open without read and write permission, for example if you only need
1643
+ /// // to call `stat` on the file
1644
+ /// let file = OpenOptions::new().access_mode(0).open("foo.txt").await?;
1645
+ /// # std::io::Result::Ok(()) });
1646
+ /// ```
1647
+ ///
1648
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
1649
+ fn access_mode ( & mut self , access : u32 ) -> & mut Self ;
1650
+
1651
+ /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with
1652
+ /// the specified value.
1653
+ ///
1654
+ /// By default `share_mode` is set to
1655
+ /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows
1656
+ /// other processes to read, write, and delete/rename the same file
1657
+ /// while it is open. Removing any of the flags will prevent other
1658
+ /// processes from performing the corresponding operation until the file
1659
+ /// handle is closed.
1660
+ ///
1661
+ /// # Examples
1662
+ ///
1663
+ /// ```no_run
1664
+ /// use async_fs::{OpenOptions, windows::OpenOptionsExt};
1665
+ ///
1666
+ /// # futures_lite::future::block_on(async {
1667
+ /// // Do not allow others to read or modify this file while we have it open
1668
+ /// // for writing.
1669
+ /// let file = OpenOptions::new()
1670
+ /// .write(true)
1671
+ /// .share_mode(0)
1672
+ /// .open("foo.txt")
1673
+ /// .await?;
1674
+ /// # std::io::Result::Ok(()) });
1675
+ /// ```
1676
+ ///
1677
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
1678
+ fn share_mode ( & mut self , val : u32 ) -> & mut Self ;
1679
+
1680
+ /// Sets extra flags for the `dwFileFlags` argument to the call to
1681
+ /// [`CreateFile2`] to the specified value (or combines it with
1682
+ /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes`
1683
+ /// for [`CreateFile`]).
1684
+ ///
1685
+ /// Custom flags can only set flags, not remove flags set by Rust's options.
1686
+ /// This option overwrites any previously set custom flags.
1687
+ ///
1688
+ /// # Examples
1689
+ ///
1690
+ /// ```no_run
1691
+ /// use async_fs::{OpenOptions, windows::OpenOptionsExt};
1692
+ ///
1693
+ /// # futures_lite::future::block_on(async {
1694
+ /// let file = OpenOptions::new()
1695
+ /// .create(true)
1696
+ /// .write(true)
1697
+ /// .custom_flags(winapi::um::winbase::FILE_FLAG_DELETE_ON_CLOSE)
1698
+ /// .open("foo.txt")
1699
+ /// .await?;
1700
+ /// # std::io::Result::Ok(()) });
1701
+ /// ```
1702
+ ///
1703
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
1704
+ /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
1705
+ fn custom_flags ( & mut self , flags : u32 ) -> & mut Self ;
1706
+
1707
+ /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to
1708
+ /// the specified value (or combines it with `custom_flags` and
1709
+ /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
1710
+ /// [`CreateFile`]).
1711
+ ///
1712
+ /// If a _new_ file is created because it does not yet exist and
1713
+ /// `.create(true)` or `.create_new(true)` are specified, the new file is
1714
+ /// given the attributes declared with `.attributes()`.
1715
+ ///
1716
+ /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
1717
+ /// existing attributes are preserved and combined with the ones declared
1718
+ /// with `.attributes()`.
1719
+ ///
1720
+ /// In all other cases the attributes get ignored.
1721
+ ///
1722
+ /// # Examples
1723
+ ///
1724
+ /// ```no_run
1725
+ /// use async_fs::{OpenOptions, windows::OpenOptionsExt};
1726
+ ///
1727
+ /// # futures_lite::future::block_on(async {
1728
+ /// let file = OpenOptions::new()
1729
+ /// .write(true)
1730
+ /// .create(true)
1731
+ /// .attributes(winapi::um::winnt::FILE_ATTRIBUTE_HIDDEN)
1732
+ /// .open("foo.txt")
1733
+ /// .await?;
1734
+ /// # std::io::Result::Ok(()) });
1735
+ /// ```
1736
+ ///
1737
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
1738
+ /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
1739
+ fn attributes ( & mut self , val : u32 ) -> & mut Self ;
1740
+
1741
+ /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to
1742
+ /// the specified value (or combines it with `custom_flags` and `attributes`
1743
+ /// to set the `dwFlagsAndAttributes` for [`CreateFile`]).
1744
+ ///
1745
+ /// By default `security_qos_flags` is not set. It should be specified when
1746
+ /// opening a named pipe, to control to which degree a server process can
1747
+ /// act on behalf of a client process (security impersonation level).
1748
+ ///
1749
+ /// When `security_qos_flags` is not set, a malicious program can gain the
1750
+ /// elevated privileges of a privileged Rust process when it allows opening
1751
+ /// user-specified paths, by tricking it into opening a named pipe. So
1752
+ /// arguably `security_qos_flags` should also be set when opening arbitrary
1753
+ /// paths. However the bits can then conflict with other flags, specifically
1754
+ /// `FILE_FLAG_OPEN_NO_RECALL`.
1755
+ ///
1756
+ /// For information about possible values, see [Impersonation Levels] on the
1757
+ /// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set
1758
+ /// automatically when using this method.
1759
+ ///
1760
+ /// # Examples
1761
+ ///
1762
+ /// ```no_run
1763
+ /// use async_fs::{OpenOptions, windows::OpenOptionsExt};
1764
+ ///
1765
+ /// # futures_lite::future::block_on(async {
1766
+ /// let file = OpenOptions::new()
1767
+ /// .write(true)
1768
+ /// .create(true)
1769
+ /// .security_qos_flags(winapi::um::winbase::SECURITY_IDENTIFICATION)
1770
+ /// .open(r"\\.\pipe\MyPipe")
1771
+ /// .await?;
1772
+ /// # std::io::Result::Ok(()) });
1773
+ /// ```
1774
+ ///
1775
+ /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
1776
+ /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
1777
+ /// [Impersonation Levels]: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
1778
+ fn security_qos_flags ( & mut self , flags : u32 ) -> & mut Self ;
1779
+ }
1540
1780
}
0 commit comments