completeio/fs/
open_options.rs

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