From 4f4f4807c3fe21cbfde82d894f044636b52cb04b Mon Sep 17 00:00:00 2001 From: Charles Hovine Date: Thu, 21 May 2020 17:18:58 +0200 Subject: [PATCH] fs: implement OpenOptionsExt for OpenOptions (#2515) Trait OpenOptionsExt is now implemented for fs::OpenOption. In order to access the underlying std::fs::OpenOptions wrapped in tokio's OpenOption, an as_inner_mut method was added to OpenOption, only visible to the parent module. Fixes: #2366 --- tokio/src/fs/open_options.rs | 6 ++ tokio/src/fs/os/unix/mod.rs | 3 + tokio/src/fs/os/unix/open_options_ext.rs | 79 ++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 tokio/src/fs/os/unix/open_options_ext.rs diff --git a/tokio/src/fs/open_options.rs b/tokio/src/fs/open_options.rs index 3210f4b7b..ba3d9a6cf 100644 --- a/tokio/src/fs/open_options.rs +++ b/tokio/src/fs/open_options.rs @@ -382,6 +382,12 @@ impl OpenOptions { let std = asyncify(move || opts.open(path)).await?; Ok(File::from_std(std)) } + + /// Returns a mutable reference to the the underlying std::fs::OpenOptions + #[cfg(unix)] + pub(super) fn as_inner_mut(&mut self) -> &mut std::fs::OpenOptions { + &mut self.0 + } } impl From for OpenOptions { diff --git a/tokio/src/fs/os/unix/mod.rs b/tokio/src/fs/os/unix/mod.rs index 030eaf8a8..826222ebf 100644 --- a/tokio/src/fs/os/unix/mod.rs +++ b/tokio/src/fs/os/unix/mod.rs @@ -3,5 +3,8 @@ mod symlink; pub use self::symlink::symlink; +mod open_options_ext; +pub use self::open_options_ext::OpenOptionsExt; + mod dir_builder_ext; pub use self::dir_builder_ext::DirBuilderExt; diff --git a/tokio/src/fs/os/unix/open_options_ext.rs b/tokio/src/fs/os/unix/open_options_ext.rs new file mode 100644 index 000000000..ff8927588 --- /dev/null +++ b/tokio/src/fs/os/unix/open_options_ext.rs @@ -0,0 +1,79 @@ +use crate::fs::open_options::OpenOptions; +use std::os::unix::fs::OpenOptionsExt as StdOpenOptionsExt; + +/// Unix-specific extensions to [`fs::OpenOptions`]. +/// +/// This mirrors the definition of [`std::os::unix::fs::OpenOptionsExt`]. +/// +/// +/// [`fs::OpenOptions`]: crate::fs::OpenOptions +/// [`std::os::unix::fs::OpenOptionsExt`]: std::os::unix::fs::OpenOptionsExt +pub trait OpenOptionsExt { + /// Sets the mode bits that a new file will be created with. + /// + /// If a new file is created as part of an `OpenOptions::open` call then this + /// specified `mode` will be used as the permission bits for the new file. + /// If no `mode` is set, the default of `0o666` will be used. + /// The operating system masks out bits with the system's `umask`, to produce + /// the final permissions. + /// + /// # Examples + /// + /// ```no_run + /// use tokio::fs::OpenOptions; + /// use tokio::fs::os::unix::OpenOptionsExt; + /// use std::io; + /// + /// #[tokio::main] + /// async fn main() -> io::Result<()> { + /// let mut options = OpenOptions::new(); + /// options.mode(0o644); // Give read/write for owner and read for others. + /// let file = options.open("foo.txt").await?; + /// + /// Ok(()) + /// } + /// ``` + fn mode(&mut self, mode: u32) -> &mut Self; + + /// Pass custom flags to the `flags` argument of `open`. + /// + /// The bits that define the access mode are masked out with `O_ACCMODE`, to + /// ensure they do not interfere with the access mode set by Rusts options. + /// + /// Custom flags can only set flags, not remove flags set by Rusts options. + /// This options overwrites any previously set custom flags. + /// + /// # Examples + /// + /// ```no_run + /// use libc; + /// use tokio::fs::OpenOptions; + /// use tokio::fs::os::unix::OpenOptionsExt; + /// use std::io; + /// + /// #[tokio::main] + /// async fn main() -> io::Result<()> { + /// let mut options = OpenOptions::new(); + /// options.write(true); + /// if cfg!(unix) { + /// options.custom_flags(libc::O_NOFOLLOW); + /// } + /// let file = options.open("foo.txt").await?; + /// + /// Ok(()) + /// } + /// ``` + fn custom_flags(&mut self, flags: i32) -> &mut Self; +} + +impl OpenOptionsExt for OpenOptions { + fn mode(&mut self, mode: u32) -> &mut OpenOptions { + self.as_inner_mut().mode(mode); + self + } + + fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { + self.as_inner_mut().custom_flags(flags); + self + } +}