Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fs: use cfgs on fns instead of OS ext traits #3264

Merged
merged 1 commit into from Dec 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 24 additions & 4 deletions tokio/src/fs/dir_builder.rs
Expand Up @@ -5,14 +5,10 @@ use std::path::Path;

/// A builder for creating directories in various manners.
///
/// Additional Unix-specific options are available via importing the
/// [`DirBuilderExt`] trait.
///
/// This is a specialized version of [`std::fs::DirBuilder`] for usage on
/// the Tokio runtime.
///
/// [std::fs::DirBuilder]: std::fs::DirBuilder
/// [`DirBuilderExt`]: crate::fs::os::unix::DirBuilderExt
#[derive(Debug, Default)]
pub struct DirBuilder {
/// Indicates whether to create parent directories if they are missing.
Expand Down Expand Up @@ -115,3 +111,27 @@ impl DirBuilder {
asyncify(move || builder.create(path)).await
}
}

feature! {
#![unix]

impl DirBuilder {
/// Sets the mode to create new directories with.
///
/// This option defaults to 0o777.
///
/// # Examples
///
///
/// ```no_run
/// use tokio::fs::DirBuilder;
///
/// let mut builder = DirBuilder::new();
/// builder.mode(0o775);
/// ```
pub fn mode(&mut self, mode: u32) -> &mut Self {
self.mode = Some(mode);
self
}
}
}
19 changes: 17 additions & 2 deletions tokio/src/fs/mod.rs
Expand Up @@ -48,8 +48,6 @@ pub use self::metadata::metadata;
mod open_options;
pub use self::open_options::OpenOptions;

pub mod os;

mod read;
pub use self::read::read;

Expand Down Expand Up @@ -86,6 +84,23 @@ pub use self::write::write;
mod copy;
pub use self::copy::copy;

feature! {
#![unix]

mod symlink;
pub use self::symlink::symlink;
}

feature! {
#![windows]

mod symlink_dir;
pub use self::symlink_dir::symlink_dir;

mod symlink_file;
pub use self::symlink_file::symlink_file;
}
Comment on lines +94 to +102
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not show up on docs.rs at all. We should do something about that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does if you pick windows? What happened before?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It did not show up previously on the default view either, but I'm pretty sure rustdoc wont complain if we compile them on windows or docsrs, since it doesn't compile the body of the functions, only their signature.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, I can give it a shot later.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gave it a shot, rustdoc did not like it due to broken intra doc links:

error: unresolved link to `std::os::windows::fs::symlink_dir`
  --> tokio/src/fs/symlink_dir.rs:13:12
   |
13 | /// [std]: std::os::windows::fs::symlink_dir
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `windows` in module `os`
   |
note: the lint level is defined here
  --> tokio/src/lib.rs:13:26
   |
13 | #![cfg_attr(docsrs, deny(broken_intra_doc_links))]
   |                          ^^^^^^^^^^^^^^^^^^^^^^

error: unresolved link to `std::os::windows::fs::symlink_file`
  --> tokio/src/fs/symlink_file.rs:13:12
   |
13 | /// [std]: std::os::windows::fs::symlink_file
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `windows` in module `os`

error: unresolved link to `std::os::windows::fs::symlink_dir`
  --> tokio/src/fs/symlink_dir.rs:13:12
   |
13 | /// [std]: std::os::windows::fs::symlink_dir
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `windows` in module `os`

The references fns do not exist in std under unix. This is non-standard, so I vote we skip unless you have another strategy to try?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. Annoying. But yes, let's not do it for now.


use std::io;

pub(crate) async fn asyncify<F, T>(f: F) -> io::Result<T>
Expand Down
256 changes: 256 additions & 0 deletions tokio/src/fs/open_options.rs
Expand Up @@ -389,6 +389,262 @@ impl OpenOptions {
}
}

feature! {
#![unix]

use std::os::unix::fs::OpenOptionsExt;

impl OpenOptions {
/// 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 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(())
/// }
/// ```
pub fn mode(&mut self, mode: u32) -> &mut OpenOptions {
self.as_inner_mut().mode(mode);
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 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(())
/// }
/// ```
pub fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
self.as_inner_mut().custom_flags(flags);
self
}
}
}

feature! {
#![windows]

use std::os::windows::fs::OpenOptionsExt;

impl OpenOptions {
/// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
/// with the specified value.
///
/// This will override the `read`, `write`, and `append` flags on the
/// `OpenOptions` structure. This method provides fine-grained control over
/// the permissions to read, write and append data, attributes (like hidden
/// and system), and extended attributes.
///
/// # Examples
///
/// ```no_run
/// use tokio::fs::OpenOptions;
///
/// # #[tokio::main]
/// # async fn main() -> std::io::Result<()> {
/// // Open without read and write permission, for example if you only need
/// // to call `stat` on the file
/// let file = OpenOptions::new().access_mode(0).open("foo.txt").await?;
/// # Ok(())
/// # }
/// ```
///
/// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
pub fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
self.as_inner_mut().access_mode(access);
self
}

/// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with
/// the specified value.
///
/// By default `share_mode` is set to
/// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows
/// other processes to read, write, and delete/rename the same file
/// while it is open. Removing any of the flags will prevent other
/// processes from performing the corresponding operation until the file
/// handle is closed.
///
/// # Examples
///
/// ```no_run
/// use tokio::fs::OpenOptions;
///
/// # #[tokio::main]
/// # async fn main() -> std::io::Result<()> {
/// // Do not allow others to read or modify this file while we have it open
/// // for writing.
/// let file = OpenOptions::new()
/// .write(true)
/// .share_mode(0)
/// .open("foo.txt").await?;
/// # Ok(())
/// # }
/// ```
///
/// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
pub fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
self.as_inner_mut().share_mode(share);
self
}

/// Sets extra flags for the `dwFileFlags` argument to the call to
/// [`CreateFile2`] to the specified value (or combines it with
/// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes`
/// for [`CreateFile`]).
///
/// Custom flags can only set flags, not remove flags set by Rust's options.
/// This option overwrites any previously set custom flags.
///
/// # Examples
///
/// ```no_run
/// use winapi::um::winbase::FILE_FLAG_DELETE_ON_CLOSE;
/// use tokio::fs::OpenOptions;
///
/// # #[tokio::main]
/// # async fn main() -> std::io::Result<()> {
/// let file = OpenOptions::new()
/// .create(true)
/// .write(true)
/// .custom_flags(FILE_FLAG_DELETE_ON_CLOSE)
/// .open("foo.txt").await?;
/// # Ok(())
/// # }
/// ```
///
/// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
/// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
pub fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
self.as_inner_mut().custom_flags(flags);
self
}

/// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to
/// the specified value (or combines it with `custom_flags` and
/// `security_qos_flags` to set the `dwFlagsAndAttributes` for
/// [`CreateFile`]).
///
/// If a _new_ file is created because it does not yet exist and
/// `.create(true)` or `.create_new(true)` are specified, the new file is
/// given the attributes declared with `.attributes()`.
///
/// If an _existing_ file is opened with `.create(true).truncate(true)`, its
/// existing attributes are preserved and combined with the ones declared
/// with `.attributes()`.
///
/// In all other cases the attributes get ignored.
///
/// # Examples
///
/// ```no_run
/// use winapi::um::winnt::FILE_ATTRIBUTE_HIDDEN;
/// use tokio::fs::OpenOptions;
///
/// # #[tokio::main]
/// # async fn main() -> std::io::Result<()> {
/// let file = OpenOptions::new()
/// .write(true)
/// .create(true)
/// .attributes(FILE_ATTRIBUTE_HIDDEN)
/// .open("foo.txt").await?;
/// # Ok(())
/// # }
/// ```
///
/// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
/// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
pub fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
self.as_inner_mut().attributes(attributes);
self
}

/// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to
/// the specified value (or combines it with `custom_flags` and `attributes`
/// to set the `dwFlagsAndAttributes` for [`CreateFile`]).
///
/// By default `security_qos_flags` is not set. It should be specified when
/// opening a named pipe, to control to which degree a server process can
/// act on behalf of a client process (security impersonation level).
///
/// When `security_qos_flags` is not set, a malicious program can gain the
/// elevated privileges of a privileged Rust process when it allows opening
/// user-specified paths, by tricking it into opening a named pipe. So
/// arguably `security_qos_flags` should also be set when opening arbitrary
/// paths. However the bits can then conflict with other flags, specifically
/// `FILE_FLAG_OPEN_NO_RECALL`.
///
/// For information about possible values, see [Impersonation Levels] on the
/// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set
/// automatically when using this method.
///
/// # Examples
///
/// ```no_run
/// use winapi::um::winbase::SECURITY_IDENTIFICATION;
/// use tokio::fs::OpenOptions;
///
/// # #[tokio::main]
/// # async fn main() -> std::io::Result<()> {
/// let file = OpenOptions::new()
/// .write(true)
/// .create(true)
///
/// // Sets the flag value to `SecurityIdentification`.
/// .security_qos_flags(SECURITY_IDENTIFICATION)
///
/// .open(r"\\.\pipe\MyPipe").await?;
/// # Ok(())
/// # }
/// ```
///
/// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
/// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
/// [Impersonation Levels]:
/// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
pub fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
self.as_inner_mut().security_qos_flags(flags);
self
}
}
}

impl From<std::fs::OpenOptions> for OpenOptions {
fn from(options: std::fs::OpenOptions) -> OpenOptions {
OpenOptions(options)
Expand Down
7 changes: 0 additions & 7 deletions tokio/src/fs/os/mod.rs

This file was deleted.

36 changes: 0 additions & 36 deletions tokio/src/fs/os/unix/dir_builder_ext.rs

This file was deleted.