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}