summaryrefslogtreecommitdiffstats
path: root/third_party/rust/tokio/src/fs/open_options.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/tokio/src/fs/open_options.rs')
-rw-r--r--third_party/rust/tokio/src/fs/open_options.rs665
1 files changed, 665 insertions, 0 deletions
diff --git a/third_party/rust/tokio/src/fs/open_options.rs b/third_party/rust/tokio/src/fs/open_options.rs
new file mode 100644
index 0000000000..f3b4654741
--- /dev/null
+++ b/third_party/rust/tokio/src/fs/open_options.rs
@@ -0,0 +1,665 @@
+use crate::fs::{asyncify, File};
+
+use std::io;
+use std::path::Path;
+
+#[cfg(test)]
+mod mock_open_options;
+#[cfg(test)]
+use mock_open_options::MockOpenOptions as StdOpenOptions;
+#[cfg(not(test))]
+use std::fs::OpenOptions as StdOpenOptions;
+
+/// Options and flags which can be used to configure how a file is opened.
+///
+/// This builder exposes the ability to configure how a [`File`] is opened and
+/// what operations are permitted on the open file. The [`File::open`] and
+/// [`File::create`] methods are aliases for commonly used options using this
+/// builder.
+///
+/// Generally speaking, when using `OpenOptions`, you'll first call [`new`],
+/// then chain calls to methods to set each option, then call [`open`], passing
+/// the path of the file you're trying to open. This will give you a
+/// [`io::Result`][result] with a [`File`] inside that you can further operate
+/// on.
+///
+/// This is a specialized version of [`std::fs::OpenOptions`] for usage from
+/// the Tokio runtime.
+///
+/// `From<std::fs::OpenOptions>` is implemented for more advanced configuration
+/// than the methods provided here.
+///
+/// [`new`]: OpenOptions::new
+/// [`open`]: OpenOptions::open
+/// [result]: std::io::Result
+/// [`File`]: File
+/// [`File::open`]: File::open
+/// [`File::create`]: File::create
+/// [`std::fs::OpenOptions`]: std::fs::OpenOptions
+///
+/// # Examples
+///
+/// Opening a file to read:
+///
+/// ```no_run
+/// use tokio::fs::OpenOptions;
+/// use std::io;
+///
+/// #[tokio::main]
+/// async fn main() -> io::Result<()> {
+/// let file = OpenOptions::new()
+/// .read(true)
+/// .open("foo.txt")
+/// .await?;
+///
+/// Ok(())
+/// }
+/// ```
+///
+/// Opening a file for both reading and writing, as well as creating it if it
+/// doesn't exist:
+///
+/// ```no_run
+/// use tokio::fs::OpenOptions;
+/// use std::io;
+///
+/// #[tokio::main]
+/// async fn main() -> io::Result<()> {
+/// let file = OpenOptions::new()
+/// .read(true)
+/// .write(true)
+/// .create(true)
+/// .open("foo.txt")
+/// .await?;
+///
+/// Ok(())
+/// }
+/// ```
+#[derive(Clone, Debug)]
+pub struct OpenOptions(StdOpenOptions);
+
+impl OpenOptions {
+ /// Creates a blank new set of options ready for configuration.
+ ///
+ /// All options are initially set to `false`.
+ ///
+ /// This is an async version of [`std::fs::OpenOptions::new`][std]
+ ///
+ /// [std]: std::fs::OpenOptions::new
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::fs::OpenOptions;
+ ///
+ /// let mut options = OpenOptions::new();
+ /// let future = options.read(true).open("foo.txt");
+ /// ```
+ pub fn new() -> OpenOptions {
+ OpenOptions(StdOpenOptions::new())
+ }
+
+ /// Sets the option for read access.
+ ///
+ /// This option, when true, will indicate that the file should be
+ /// `read`-able if opened.
+ ///
+ /// This is an async version of [`std::fs::OpenOptions::read`][std]
+ ///
+ /// [std]: std::fs::OpenOptions::read
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::fs::OpenOptions;
+ /// use std::io;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let file = OpenOptions::new()
+ /// .read(true)
+ /// .open("foo.txt")
+ /// .await?;
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ pub fn read(&mut self, read: bool) -> &mut OpenOptions {
+ self.0.read(read);
+ self
+ }
+
+ /// Sets the option for write access.
+ ///
+ /// This option, when true, will indicate that the file should be
+ /// `write`-able if opened.
+ ///
+ /// This is an async version of [`std::fs::OpenOptions::write`][std]
+ ///
+ /// [std]: std::fs::OpenOptions::write
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::fs::OpenOptions;
+ /// use std::io;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .open("foo.txt")
+ /// .await?;
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ pub fn write(&mut self, write: bool) -> &mut OpenOptions {
+ self.0.write(write);
+ self
+ }
+
+ /// Sets the option for the append mode.
+ ///
+ /// This option, when true, means that writes will append to a file instead
+ /// of overwriting previous contents. Note that setting
+ /// `.write(true).append(true)` has the same effect as setting only
+ /// `.append(true)`.
+ ///
+ /// For most filesystems, the operating system guarantees that all writes are
+ /// atomic: no writes get mangled because another process writes at the same
+ /// time.
+ ///
+ /// One maybe obvious note when using append-mode: make sure that all data
+ /// that belongs together is written to the file in one operation. This
+ /// can be done by concatenating strings before passing them to [`write()`],
+ /// or using a buffered writer (with a buffer of adequate size),
+ /// and calling [`flush()`] when the message is complete.
+ ///
+ /// If a file is opened with both read and append access, beware that after
+ /// opening, and after every write, the position for reading may be set at the
+ /// end of the file. So, before writing, save the current position (using
+ /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`), and restore it before the next read.
+ ///
+ /// This is an async version of [`std::fs::OpenOptions::append`][std]
+ ///
+ /// [std]: std::fs::OpenOptions::append
+ ///
+ /// ## Note
+ ///
+ /// This function doesn't create the file if it doesn't exist. Use the [`create`]
+ /// method to do so.
+ ///
+ /// [`write()`]: crate::io::AsyncWriteExt::write
+ /// [`flush()`]: crate::io::AsyncWriteExt::flush
+ /// [`seek`]: crate::io::AsyncSeekExt::seek
+ /// [`SeekFrom`]: std::io::SeekFrom
+ /// [`Current`]: std::io::SeekFrom::Current
+ /// [`create`]: OpenOptions::create
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::fs::OpenOptions;
+ /// use std::io;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let file = OpenOptions::new()
+ /// .append(true)
+ /// .open("foo.txt")
+ /// .await?;
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ pub fn append(&mut self, append: bool) -> &mut OpenOptions {
+ self.0.append(append);
+ self
+ }
+
+ /// Sets the option for truncating a previous file.
+ ///
+ /// If a file is successfully opened with this option set it will truncate
+ /// the file to 0 length if it already exists.
+ ///
+ /// The file must be opened with write access for truncate to work.
+ ///
+ /// This is an async version of [`std::fs::OpenOptions::truncate`][std]
+ ///
+ /// [std]: std::fs::OpenOptions::truncate
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::fs::OpenOptions;
+ /// use std::io;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .truncate(true)
+ /// .open("foo.txt")
+ /// .await?;
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
+ self.0.truncate(truncate);
+ self
+ }
+
+ /// Sets the option for creating a new file.
+ ///
+ /// This option indicates whether a new file will be created if the file
+ /// does not yet already exist.
+ ///
+ /// In order for the file to be created, [`write`] or [`append`] access must
+ /// be used.
+ ///
+ /// This is an async version of [`std::fs::OpenOptions::create`][std]
+ ///
+ /// [std]: std::fs::OpenOptions::create
+ /// [`write`]: OpenOptions::write
+ /// [`append`]: OpenOptions::append
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::fs::OpenOptions;
+ /// use std::io;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .create(true)
+ /// .open("foo.txt")
+ /// .await?;
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ pub fn create(&mut self, create: bool) -> &mut OpenOptions {
+ self.0.create(create);
+ self
+ }
+
+ /// Sets the option to always create a new file.
+ ///
+ /// This option indicates whether a new file will be created. No file is
+ /// allowed to exist at the target location, also no (dangling) symlink.
+ ///
+ /// This option is useful because it is atomic. Otherwise between checking
+ /// whether a file exists and creating a new one, the file may have been
+ /// created by another process (a TOCTOU race condition / attack).
+ ///
+ /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
+ /// ignored.
+ ///
+ /// The file must be opened with write or append access in order to create a
+ /// new file.
+ ///
+ /// This is an async version of [`std::fs::OpenOptions::create_new`][std]
+ ///
+ /// [std]: std::fs::OpenOptions::create_new
+ /// [`.create()`]: OpenOptions::create
+ /// [`.truncate()`]: OpenOptions::truncate
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::fs::OpenOptions;
+ /// use std::io;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let file = OpenOptions::new()
+ /// .write(true)
+ /// .create_new(true)
+ /// .open("foo.txt")
+ /// .await?;
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
+ self.0.create_new(create_new);
+ self
+ }
+
+ /// Opens a file at `path` with the options specified by `self`.
+ ///
+ /// This is an async version of [`std::fs::OpenOptions::open`][std]
+ ///
+ /// [std]: std::fs::OpenOptions::open
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error under a number of different
+ /// circumstances. Some of these error conditions are listed here, together
+ /// with their [`ErrorKind`]. The mapping to [`ErrorKind`]s is not part of
+ /// the compatibility contract of the function, especially the `Other` kind
+ /// might change to more specific kinds in the future.
+ ///
+ /// * [`NotFound`]: The specified file does not exist and neither `create`
+ /// or `create_new` is set.
+ /// * [`NotFound`]: One of the directory components of the file path does
+ /// not exist.
+ /// * [`PermissionDenied`]: The user lacks permission to get the specified
+ /// access rights for the file.
+ /// * [`PermissionDenied`]: The user lacks permission to open one of the
+ /// directory components of the specified path.
+ /// * [`AlreadyExists`]: `create_new` was specified and the file already
+ /// exists.
+ /// * [`InvalidInput`]: Invalid combinations of open options (truncate
+ /// without write access, no access mode set, etc.).
+ /// * [`Other`]: One of the directory components of the specified file path
+ /// was not, in fact, a directory.
+ /// * [`Other`]: Filesystem-level errors: full disk, write permission
+ /// requested on a read-only file system, exceeded disk quota, too many
+ /// open files, too long filename, too many symbolic links in the
+ /// specified path (Unix-like systems only), etc.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::fs::OpenOptions;
+ /// use std::io;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let file = OpenOptions::new().open("foo.txt").await?;
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`ErrorKind`]: std::io::ErrorKind
+ /// [`AlreadyExists`]: std::io::ErrorKind::AlreadyExists
+ /// [`InvalidInput`]: std::io::ErrorKind::InvalidInput
+ /// [`NotFound`]: std::io::ErrorKind::NotFound
+ /// [`Other`]: std::io::ErrorKind::Other
+ /// [`PermissionDenied`]: std::io::ErrorKind::PermissionDenied
+ pub async fn open(&self, path: impl AsRef<Path>) -> io::Result<File> {
+ let path = path.as_ref().to_owned();
+ let opts = self.0.clone();
+
+ let std = asyncify(move || opts.open(path)).await?;
+ Ok(File::from_std(std))
+ }
+
+ /// Returns a mutable reference to the underlying `std::fs::OpenOptions`
+ pub(super) fn as_inner_mut(&mut self) -> &mut StdOpenOptions {
+ &mut self.0
+ }
+}
+
+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
+ }
+
+ /// Passes 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<StdOpenOptions> for OpenOptions {
+ fn from(options: StdOpenOptions) -> OpenOptions {
+ OpenOptions(options)
+ }
+}
+
+impl Default for OpenOptions {
+ fn default() -> Self {
+ Self::new()
+ }
+}