• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::fs::OpenOptions as SyncOpenOptions;
15 use std::io;
16 use std::path::Path;
17 
18 use crate::fs::{async_op, File};
19 
20 /// An asynchronous version of the [`std::fs::OpenOptions`];
21 ///
22 /// Options and flags which can be used to configure how a file is opened.
23 ///
24 /// ```no_run
25 /// use ylong_runtime::fs::OpenOptions;
26 ///
27 /// async fn open_with_options() {
28 ///     let file = OpenOptions::new()
29 ///         .read(true)
30 ///         .write(true)
31 ///         .create(true)
32 ///         .open("foo.txt")
33 ///         .await;
34 /// }
35 /// ```
36 #[derive(Clone, Debug)]
37 pub struct OpenOptions(SyncOpenOptions);
38 
39 impl OpenOptions {
40     /// Creates a blank new set of options ready for configuration when opening
41     /// a file.
42     ///
43     /// All options are initially set to `false` just like
44     /// [`std::fs::OpenOptions::new`].
45     ///
46     /// # Examples
47     ///
48     /// ```no_run
49     /// use ylong_runtime::fs::OpenOptions;
50     ///
51     /// async fn create_option() {
52     ///     let mut options = OpenOptions::new();
53     ///     let file = options.read(true).open("foo.txt").await;
54     /// }
55     /// ```
56     // Prevent to increase binary size and thus mask this warning.
57     #[allow(clippy::new_without_default)]
new() -> OpenOptions58     pub fn new() -> OpenOptions {
59         OpenOptions(SyncOpenOptions::new())
60     }
61 
62     /// Sets the option for file read access.
63     ///
64     /// This option, when true, will indicate that the file should be
65     /// `read`-able if opened.
66     ///
67     /// This method's behavior is the same as [`std::fs::OpenOptions::read`].
68     ///
69     /// # Examples
70     ///
71     /// ```no_run
72     /// use ylong_runtime::fs::OpenOptions;
73     ///
74     /// async fn open_with_read() {
75     ///     let file = OpenOptions::new().read(true).open("foo.txt").await;
76     /// }
77     /// ```
read(&mut self, read: bool) -> &mut OpenOptions78     pub fn read(&mut self, read: bool) -> &mut OpenOptions {
79         self.0.read(read);
80         self
81     }
82 
83     /// Sets the option for file write access.
84     ///
85     /// This option, when true, will indicate that the file should be
86     /// `write`-able if opened.
87     ///
88     /// If the file already exists, any write calls on it will overwrite its
89     /// previous contents, without truncating it.
90     ///
91     /// This method's behavior is the same as [`std::fs::OpenOptions::write`].
92     ///
93     /// # Examples
94     ///
95     /// ```no_run
96     /// use ylong_runtime::fs::OpenOptions;
97     ///
98     /// async fn open_with_write() {
99     ///     let file = OpenOptions::new().write(true).open("foo.txt").await;
100     /// }
101     /// ```
write(&mut self, write: bool) -> &mut OpenOptions102     pub fn write(&mut self, write: bool) -> &mut OpenOptions {
103         self.0.write(write);
104         self
105     }
106 
107     /// Sets the option for the file append mode.
108     ///
109     /// This option, when true, means that writes will append to a file instead
110     /// of overwriting previous contents.
111     ///
112     /// Note that when setting `.append(true)`, file write access will also be
113     /// turned on
114     ///
115     /// For most filesystems, the operating system guarantees that all writes
116     /// are atomic: no writes get mangled because another thread or process
117     /// writes at the same time.
118     ///
119     /// User should write all data that belongs together in one operation during
120     /// appending. This can be done by concatenating strings before passing
121     /// them to [`write()`], or using a buffered writer (with a buffer of
122     /// adequate size), and calling [`flush()`] when the message is written
123     /// completely.
124     ///
125     /// If a file is opened with both read and append access, beware that after
126     /// opening and every write, the position for reading may be set at the end
127     /// of the file. So, before writing, save the current position, and
128     /// restore it before the next read.
129     ///
130     /// This method's behavior is the same as [`std::fs::OpenOptions::append`].
131     ///
132     /// ## Note
133     ///
134     /// This method doesn't create the file if it doesn't exist. Use the
135     /// [`OpenOptions::create`] method to do so.
136     ///
137     /// [`write()`]: crate::io::AsyncWriteExt::write
138     /// [`flush()`]: crate::io::AsyncWrite::poll_flush
139     /// [seek]: crate::io::AsyncSeekExt::seek
140     ///
141     /// # Examples
142     ///
143     /// ```no_run
144     /// use ylong_runtime::fs::OpenOptions;
145     ///
146     /// async fn open_with_append() {
147     ///     let file = OpenOptions::new().append(true).open("foo.txt").await;
148     /// }
149     /// ```
append(&mut self, append: bool) -> &mut OpenOptions150     pub fn append(&mut self, append: bool) -> &mut OpenOptions {
151         self.0.append(append);
152         self
153     }
154 
155     /// Sets the option for truncating a file's previous content.
156     ///
157     /// If a file is successfully opened with this option set, it will truncate
158     /// the file to 0 length if it already exists. Any already-existed content
159     /// in this file will be dropped.
160     ///
161     /// The file must be opened with write access for truncate to work, which is
162     /// different from append mode.
163     ///
164     /// This method's behavior is the same as
165     /// [`std::fs::OpenOptions::truncate`].
166     ///
167     /// # Examples
168     ///
169     /// ```no_run
170     /// use ylong_runtime::fs::OpenOptions;
171     ///
172     /// async fn open_with_truncate() {
173     ///     let file = OpenOptions::new()
174     ///         .write(true)
175     ///         .truncate(true)
176     ///         .open("foo.txt")
177     ///         .await;
178     /// }
179     /// ```
truncate(&mut self, truncate: bool) -> &mut Self180     pub fn truncate(&mut self, truncate: bool) -> &mut Self {
181         self.0.truncate(truncate);
182         self
183     }
184 
185     /// Sets the option to create a new file if it doesn't already exist, or
186     /// simply open it if it does exist.
187     ///
188     /// In order for the file to be created, [`OpenOptions::write`] or
189     /// [`OpenOptions::append`] access must be set to true.
190     ///
191     /// This method's behavior is the same as [`std::fs::OpenOptions::create`].
192     ///
193     /// # Examples
194     ///
195     /// ```no_run
196     /// use ylong_runtime::fs::OpenOptions;
197     ///
198     /// async fn open_with_create() {
199     ///     let file = OpenOptions::new()
200     ///         .write(true)
201     ///         .create(true)
202     ///         .open("foo.txt")
203     ///         .await;
204     /// }
205     /// ```
create(&mut self, create: bool) -> &mut Self206     pub fn create(&mut self, create: bool) -> &mut Self {
207         self.0.create(create);
208         self
209     }
210 
211     /// Sets the option to create a new file.
212     ///
213     /// If the file already exists, opening the file with the option set will
214     /// cause an error.
215     ///
216     /// No file is allowed to exist at the target location, also no (dangling)
217     /// symlink. In this way, if the call succeeds, the file returned is
218     /// guaranteed to be new.
219     ///
220     /// This option guarantees the operation of checking whether a file exists
221     /// and creating a new one is atomic.
222     ///
223     /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
224     /// ignored.
225     ///
226     /// The file must be opened with write or append mode in order to create
227     /// a new file.
228     ///
229     /// [`.create(true)`]: OpenOptions::create
230     /// [`.truncate(true)`]: OpenOptions::truncate
231     ///
232     /// This method's behavior is the same as
233     /// [`std::fs::OpenOptions::create_new`].
234     ///
235     /// # Examples
236     ///
237     /// ```no_run
238     /// use ylong_runtime::fs::OpenOptions;
239     ///
240     /// async fn open_with_create_new() {
241     ///     let file = OpenOptions::new()
242     ///         .write(true)
243     ///         .create_new(true)
244     ///         .open("foo.txt")
245     ///         .await;
246     /// }
247     /// ```
create_new(&mut self, create_new: bool) -> &mut Self248     pub fn create_new(&mut self, create_new: bool) -> &mut Self {
249         self.0.create_new(create_new);
250         self
251     }
252 
253     /// Asynchronously opens a file at `path` with the options specified by
254     /// `self`.
255     ///
256     /// # Errors
257     ///
258     /// This method's behavior is the same as [`std::fs::OpenOptions::open`].
259     ///
260     /// * [`NotFound`]: The specified file does not exist and neither `create`
261     ///   or `create_new` is set.
262     /// * [`NotFound`]: One of the directory components of the file path doesn't
263     ///   exist.
264     /// * [`PermissionDenied`]: The user doesn't has permission to get the
265     ///   specified access rights for the file.
266     /// * [`PermissionDenied`]: The user doesn't has permission to open one of
267     ///   the directory components of the specified path.
268     /// * [`AlreadyExists`]: `create_new` was specified and the file already
269     ///   exists.
270     /// * [`InvalidInput`]: Invalid combinations of open options (truncate
271     ///   without write access, no access mode set, etc.).
272     ///
273     /// The following errors don't match any existing [`io::ErrorKind`] at the
274     /// moment:
275     /// * One of the directory components of the specified file path was not, in
276     ///   fact, a directory.
277     /// * Filesystem-level errors: full disk, write permission requested on a
278     ///   read-only file system, exceeded disk quota, too many open files, too
279     ///   long filename, too many symbolic links in the specified path
280     ///   (Unix-like systems only), etc.
281     ///
282     /// [`NotFound`]: std::io::ErrorKind::NotFound
283     /// [`PermissionDenied`]: std::io::ErrorKind::PermissionDenied
284     /// [`AlreadyExists`]: std::io::ErrorKind::AlreadyExists
285     /// [`InvalidInput`]: std::io::ErrorKind::InvalidInput
286     /// # Examples
287     ///
288     /// ```no_run
289     /// use ylong_runtime::fs::OpenOptions;
290     ///
291     /// async fn option_open() {
292     ///     let file = OpenOptions::new().read(true).open("foo.txt").await;
293     /// }
294     /// ```
open<P: AsRef<Path>>(&self, path: P) -> io::Result<File>295     pub async fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
296         let path = path.as_ref().to_owned();
297         let options = self.0.clone();
298         let file = async_op(move || options.open(path)).await?;
299         Ok(File::new(file))
300     }
301 }
302 #[cfg(all(test, target_os = "linux"))]
303 mod test {
304     use crate::fs::OpenOptions;
305 
306     /// UT test cases for Openoption.
307 
308     /// # Brief
309     /// 1. Call `read`、`write`、`append`、`truncate`、`create`、`create_new`
310     ///    function, passing in the specified parameters.
311     /// 2. Check if the settings are correct.
312     #[cfg(target_os = "linux")]
313     #[test]
ut_set_openoption()314     fn ut_set_openoption() {
315         let mut option = OpenOptions::new();
316         option.read(true);
317         option.write(true);
318         option.append(true);
319         option.truncate(true);
320         option.create(true);
321         option.create_new(true);
322         assert_eq!("OpenOptions(OpenOptions { read: true, write: true, append: true, truncate: true, create: true, create_new: true, custom_flags: 0, mode: 438 })", format!("{:?}", option.0))
323     }
324 }
325