1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
use std::{fs::OpenOptions as StdOpenOptions, io, path::Path};
use crate::File;
/// 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
/// [`OpenOptions::new`], then chain calls to methods to set each option, then
/// call [`OpenOptions::open`], passing the path of the file you're trying to
/// open. This will give you a [`std::io::Result`] with a [`File`] inside that
/// you can further operate on.
///
/// # Examples
///
/// Opening a file to read:
///
/// ```no_run
/// use compio_fs::OpenOptions;
///
/// let file = OpenOptions::new().read(true).open("foo.txt").unwrap();
/// ```
///
/// Opening a file for both reading and writing, as well as creating it if it
/// doesn't exist:
///
/// ```no_run
/// use compio_fs::OpenOptions;
///
/// let file = OpenOptions::new()
/// .read(true)
/// .write(true)
/// .create(true)
/// .open("foo.txt")
/// .unwrap();
/// ```
#[derive(Debug, Clone)]
pub struct OpenOptions(pub(crate) StdOpenOptions);
impl OpenOptions {
/// Creates a blank new set of options ready for configuration.
#[allow(clippy::new_without_default)]
#[must_use]
pub fn new() -> Self {
Self(StdOpenOptions::new())
}
/// Sets the option for read access.
///
/// This option, when true, will indicate that the file should be
/// `read`-able if opened.
pub fn read(mut self, read: bool) -> Self {
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.
pub fn write(mut self, write: bool) -> Self {
self.0.write(write);
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.
pub fn truncate(mut self, truncate: bool) -> Self {
self.0.truncate(truncate);
self
}
/// Sets the option to create a new file, or open it if it already exists.
///
/// In order for the file to be created, [`OpenOptions::write`] access must
/// be used.
pub fn create(mut self, create: bool) -> Self {
self.0.create(create);
self
}
/// Sets the option to create a new file, failing if it already exists.
///
/// No file is allowed to exist at the target location, also no (dangling)
/// symlink. In this way, if the call succeeds, the file returned is
/// guaranteed to be new.
///
/// 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.
///
/// [`.create()`]: OpenOptions::create
/// [`.truncate()`]: OpenOptions::truncate
pub fn create_new(mut self, create_new: bool) -> Self {
self.0.create_new(create_new);
self
}
/// Opens a file at `path` with the options specified by `self`.
///
/// See [`std::fs::OpenOptions::open`].
pub fn open(self, path: impl AsRef<Path>) -> io::Result<File> {
File::with_options(path, self)
}
}