• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::fs::{asyncify, File};
2 
3 use std::io;
4 use std::path::Path;
5 
6 #[cfg(test)]
7 mod mock_open_options;
8 #[cfg(test)]
9 use mock_open_options::MockOpenOptions as StdOpenOptions;
10 #[cfg(not(test))]
11 use std::fs::OpenOptions as StdOpenOptions;
12 
13 #[cfg(unix)]
14 use std::os::unix::fs::OpenOptionsExt;
15 #[cfg(windows)]
16 use std::os::windows::fs::OpenOptionsExt;
17 
18 /// Options and flags which can be used to configure how a file is opened.
19 ///
20 /// This builder exposes the ability to configure how a [`File`] is opened and
21 /// what operations are permitted on the open file. The [`File::open`] and
22 /// [`File::create`] methods are aliases for commonly used options using this
23 /// builder.
24 ///
25 /// Generally speaking, when using `OpenOptions`, you'll first call [`new`],
26 /// then chain calls to methods to set each option, then call [`open`], passing
27 /// the path of the file you're trying to open. This will give you a
28 /// [`io::Result`][result] with a [`File`] inside that you can further operate
29 /// on.
30 ///
31 /// This is a specialized version of [`std::fs::OpenOptions`] for usage from
32 /// the Tokio runtime.
33 ///
34 /// `From<std::fs::OpenOptions>` is implemented for more advanced configuration
35 /// than the methods provided here.
36 ///
37 /// [`new`]: OpenOptions::new
38 /// [`open`]: OpenOptions::open
39 /// [result]: std::io::Result
40 /// [`File`]: File
41 /// [`File::open`]: File::open
42 /// [`File::create`]: File::create
43 /// [`std::fs::OpenOptions`]: std::fs::OpenOptions
44 ///
45 /// # Examples
46 ///
47 /// Opening a file to read:
48 ///
49 /// ```no_run
50 /// use tokio::fs::OpenOptions;
51 /// use std::io;
52 ///
53 /// #[tokio::main]
54 /// async fn main() -> io::Result<()> {
55 ///     let file = OpenOptions::new()
56 ///         .read(true)
57 ///         .open("foo.txt")
58 ///         .await?;
59 ///
60 ///     Ok(())
61 /// }
62 /// ```
63 ///
64 /// Opening a file for both reading and writing, as well as creating it if it
65 /// doesn't exist:
66 ///
67 /// ```no_run
68 /// use tokio::fs::OpenOptions;
69 /// use std::io;
70 ///
71 /// #[tokio::main]
72 /// async fn main() -> io::Result<()> {
73 ///     let file = OpenOptions::new()
74 ///         .read(true)
75 ///         .write(true)
76 ///         .create(true)
77 ///         .open("foo.txt")
78 ///         .await?;
79 ///
80 ///     Ok(())
81 /// }
82 /// ```
83 #[derive(Clone, Debug)]
84 pub struct OpenOptions(StdOpenOptions);
85 
86 impl OpenOptions {
87     /// Creates a blank new set of options ready for configuration.
88     ///
89     /// All options are initially set to `false`.
90     ///
91     /// This is an async version of [`std::fs::OpenOptions::new`][std]
92     ///
93     /// [std]: std::fs::OpenOptions::new
94     ///
95     /// # Examples
96     ///
97     /// ```no_run
98     /// use tokio::fs::OpenOptions;
99     ///
100     /// let mut options = OpenOptions::new();
101     /// let future = options.read(true).open("foo.txt");
102     /// ```
new() -> OpenOptions103     pub fn new() -> OpenOptions {
104         OpenOptions(StdOpenOptions::new())
105     }
106 
107     /// Sets the option for read access.
108     ///
109     /// This option, when true, will indicate that the file should be
110     /// `read`-able if opened.
111     ///
112     /// This is an async version of [`std::fs::OpenOptions::read`][std]
113     ///
114     /// [std]: std::fs::OpenOptions::read
115     ///
116     /// # Examples
117     ///
118     /// ```no_run
119     /// use tokio::fs::OpenOptions;
120     /// use std::io;
121     ///
122     /// #[tokio::main]
123     /// async fn main() -> io::Result<()> {
124     ///     let file = OpenOptions::new()
125     ///         .read(true)
126     ///         .open("foo.txt")
127     ///         .await?;
128     ///
129     ///     Ok(())
130     /// }
131     /// ```
read(&mut self, read: bool) -> &mut OpenOptions132     pub fn read(&mut self, read: bool) -> &mut OpenOptions {
133         self.0.read(read);
134         self
135     }
136 
137     /// Sets the option for write access.
138     ///
139     /// This option, when true, will indicate that the file should be
140     /// `write`-able if opened.
141     ///
142     /// This is an async version of [`std::fs::OpenOptions::write`][std]
143     ///
144     /// [std]: std::fs::OpenOptions::write
145     ///
146     /// # Examples
147     ///
148     /// ```no_run
149     /// use tokio::fs::OpenOptions;
150     /// use std::io;
151     ///
152     /// #[tokio::main]
153     /// async fn main() -> io::Result<()> {
154     ///     let file = OpenOptions::new()
155     ///         .write(true)
156     ///         .open("foo.txt")
157     ///         .await?;
158     ///
159     ///     Ok(())
160     /// }
161     /// ```
write(&mut self, write: bool) -> &mut OpenOptions162     pub fn write(&mut self, write: bool) -> &mut OpenOptions {
163         self.0.write(write);
164         self
165     }
166 
167     /// Sets the option for the append mode.
168     ///
169     /// This option, when true, means that writes will append to a file instead
170     /// of overwriting previous contents.  Note that setting
171     /// `.write(true).append(true)` has the same effect as setting only
172     /// `.append(true)`.
173     ///
174     /// For most filesystems, the operating system guarantees that all writes are
175     /// atomic: no writes get mangled because another process writes at the same
176     /// time.
177     ///
178     /// One maybe obvious note when using append-mode: make sure that all data
179     /// that belongs together is written to the file in one operation. This
180     /// can be done by concatenating strings before passing them to [`write()`],
181     /// or using a buffered writer (with a buffer of adequate size),
182     /// and calling [`flush()`] when the message is complete.
183     ///
184     /// If a file is opened with both read and append access, beware that after
185     /// opening, and after every write, the position for reading may be set at the
186     /// end of the file. So, before writing, save the current position (using
187     /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`), and restore it before the next read.
188     ///
189     /// This is an async version of [`std::fs::OpenOptions::append`][std]
190     ///
191     /// [std]: std::fs::OpenOptions::append
192     ///
193     /// ## Note
194     ///
195     /// This function doesn't create the file if it doesn't exist. Use the [`create`]
196     /// method to do so.
197     ///
198     /// [`write()`]: crate::io::AsyncWriteExt::write
199     /// [`flush()`]: crate::io::AsyncWriteExt::flush
200     /// [`seek`]: crate::io::AsyncSeekExt::seek
201     /// [`SeekFrom`]: std::io::SeekFrom
202     /// [`Current`]: std::io::SeekFrom::Current
203     /// [`create`]: OpenOptions::create
204     ///
205     /// # Examples
206     ///
207     /// ```no_run
208     /// use tokio::fs::OpenOptions;
209     /// use std::io;
210     ///
211     /// #[tokio::main]
212     /// async fn main() -> io::Result<()> {
213     ///     let file = OpenOptions::new()
214     ///         .append(true)
215     ///         .open("foo.txt")
216     ///         .await?;
217     ///
218     ///     Ok(())
219     /// }
220     /// ```
append(&mut self, append: bool) -> &mut OpenOptions221     pub fn append(&mut self, append: bool) -> &mut OpenOptions {
222         self.0.append(append);
223         self
224     }
225 
226     /// Sets the option for truncating a previous file.
227     ///
228     /// If a file is successfully opened with this option set it will truncate
229     /// the file to 0 length if it already exists.
230     ///
231     /// The file must be opened with write access for truncate to work.
232     ///
233     /// This is an async version of [`std::fs::OpenOptions::truncate`][std]
234     ///
235     /// [std]: std::fs::OpenOptions::truncate
236     ///
237     /// # Examples
238     ///
239     /// ```no_run
240     /// use tokio::fs::OpenOptions;
241     /// use std::io;
242     ///
243     /// #[tokio::main]
244     /// async fn main() -> io::Result<()> {
245     ///     let file = OpenOptions::new()
246     ///         .write(true)
247     ///         .truncate(true)
248     ///         .open("foo.txt")
249     ///         .await?;
250     ///
251     ///     Ok(())
252     /// }
253     /// ```
truncate(&mut self, truncate: bool) -> &mut OpenOptions254     pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
255         self.0.truncate(truncate);
256         self
257     }
258 
259     /// Sets the option for creating a new file.
260     ///
261     /// This option indicates whether a new file will be created if the file
262     /// does not yet already exist.
263     ///
264     /// In order for the file to be created, [`write`] or [`append`] access must
265     /// be used.
266     ///
267     /// This is an async version of [`std::fs::OpenOptions::create`][std]
268     ///
269     /// [std]: std::fs::OpenOptions::create
270     /// [`write`]: OpenOptions::write
271     /// [`append`]: OpenOptions::append
272     ///
273     /// # Examples
274     ///
275     /// ```no_run
276     /// use tokio::fs::OpenOptions;
277     /// use std::io;
278     ///
279     /// #[tokio::main]
280     /// async fn main() -> io::Result<()> {
281     ///     let file = OpenOptions::new()
282     ///         .write(true)
283     ///         .create(true)
284     ///         .open("foo.txt")
285     ///         .await?;
286     ///
287     ///     Ok(())
288     /// }
289     /// ```
create(&mut self, create: bool) -> &mut OpenOptions290     pub fn create(&mut self, create: bool) -> &mut OpenOptions {
291         self.0.create(create);
292         self
293     }
294 
295     /// Sets the option to always create a new file.
296     ///
297     /// This option indicates whether a new file will be created.  No file is
298     /// allowed to exist at the target location, also no (dangling) symlink.
299     ///
300     /// This option is useful because it is atomic. Otherwise between checking
301     /// whether a file exists and creating a new one, the file may have been
302     /// created by another process (a TOCTOU race condition / attack).
303     ///
304     /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
305     /// ignored.
306     ///
307     /// The file must be opened with write or append access in order to create a
308     /// new file.
309     ///
310     /// This is an async version of [`std::fs::OpenOptions::create_new`][std]
311     ///
312     /// [std]: std::fs::OpenOptions::create_new
313     /// [`.create()`]: OpenOptions::create
314     /// [`.truncate()`]: OpenOptions::truncate
315     ///
316     /// # Examples
317     ///
318     /// ```no_run
319     /// use tokio::fs::OpenOptions;
320     /// use std::io;
321     ///
322     /// #[tokio::main]
323     /// async fn main() -> io::Result<()> {
324     ///     let file = OpenOptions::new()
325     ///         .write(true)
326     ///         .create_new(true)
327     ///         .open("foo.txt")
328     ///         .await?;
329     ///
330     ///     Ok(())
331     /// }
332     /// ```
create_new(&mut self, create_new: bool) -> &mut OpenOptions333     pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
334         self.0.create_new(create_new);
335         self
336     }
337 
338     /// Opens a file at `path` with the options specified by `self`.
339     ///
340     /// This is an async version of [`std::fs::OpenOptions::open`][std]
341     ///
342     /// [std]: std::fs::OpenOptions::open
343     ///
344     /// # Errors
345     ///
346     /// This function will return an error under a number of different
347     /// circumstances. Some of these error conditions are listed here, together
348     /// with their [`ErrorKind`]. The mapping to [`ErrorKind`]s is not part of
349     /// the compatibility contract of the function, especially the `Other` kind
350     /// might change to more specific kinds in the future.
351     ///
352     /// * [`NotFound`]: The specified file does not exist and neither `create`
353     ///   or `create_new` is set.
354     /// * [`NotFound`]: One of the directory components of the file path does
355     ///   not exist.
356     /// * [`PermissionDenied`]: The user lacks permission to get the specified
357     ///   access rights for the file.
358     /// * [`PermissionDenied`]: The user lacks permission to open one of the
359     ///   directory components of the specified path.
360     /// * [`AlreadyExists`]: `create_new` was specified and the file already
361     ///   exists.
362     /// * [`InvalidInput`]: Invalid combinations of open options (truncate
363     ///   without write access, no access mode set, etc.).
364     /// * [`Other`]: One of the directory components of the specified file path
365     ///   was not, in fact, a directory.
366     /// * [`Other`]: Filesystem-level errors: full disk, write permission
367     ///   requested on a read-only file system, exceeded disk quota, too many
368     ///   open files, too long filename, too many symbolic links in the
369     ///   specified path (Unix-like systems only), etc.
370     ///
371     /// # Examples
372     ///
373     /// ```no_run
374     /// use tokio::fs::OpenOptions;
375     /// use std::io;
376     ///
377     /// #[tokio::main]
378     /// async fn main() -> io::Result<()> {
379     ///     let file = OpenOptions::new().open("foo.txt").await?;
380     ///     Ok(())
381     /// }
382     /// ```
383     ///
384     /// [`ErrorKind`]: std::io::ErrorKind
385     /// [`AlreadyExists`]: std::io::ErrorKind::AlreadyExists
386     /// [`InvalidInput`]: std::io::ErrorKind::InvalidInput
387     /// [`NotFound`]: std::io::ErrorKind::NotFound
388     /// [`Other`]: std::io::ErrorKind::Other
389     /// [`PermissionDenied`]: std::io::ErrorKind::PermissionDenied
open(&self, path: impl AsRef<Path>) -> io::Result<File>390     pub async fn open(&self, path: impl AsRef<Path>) -> io::Result<File> {
391         let path = path.as_ref().to_owned();
392         let opts = self.0.clone();
393 
394         let std = asyncify(move || opts.open(path)).await?;
395         Ok(File::from_std(std))
396     }
397 
398     /// Returns a mutable reference to the underlying `std::fs::OpenOptions`
as_inner_mut(&mut self) -> &mut StdOpenOptions399     pub(super) fn as_inner_mut(&mut self) -> &mut StdOpenOptions {
400         &mut self.0
401     }
402 }
403 
404 feature! {
405     #![unix]
406 
407     impl OpenOptions {
408         /// Sets the mode bits that a new file will be created with.
409         ///
410         /// If a new file is created as part of an `OpenOptions::open` call then this
411         /// specified `mode` will be used as the permission bits for the new file.
412         /// If no `mode` is set, the default of `0o666` will be used.
413         /// The operating system masks out bits with the system's `umask`, to produce
414         /// the final permissions.
415         ///
416         /// # Examples
417         ///
418         /// ```no_run
419         /// use tokio::fs::OpenOptions;
420         /// use std::io;
421         ///
422         /// #[tokio::main]
423         /// async fn main() -> io::Result<()> {
424         ///     let mut options = OpenOptions::new();
425         ///     options.mode(0o644); // Give read/write for owner and read for others.
426         ///     let file = options.open("foo.txt").await?;
427         ///
428         ///     Ok(())
429         /// }
430         /// ```
431         pub fn mode(&mut self, mode: u32) -> &mut OpenOptions {
432             self.as_inner_mut().mode(mode);
433             self
434         }
435 
436         /// Passes custom flags to the `flags` argument of `open`.
437         ///
438         /// The bits that define the access mode are masked out with `O_ACCMODE`, to
439         /// ensure they do not interfere with the access mode set by Rusts options.
440         ///
441         /// Custom flags can only set flags, not remove flags set by Rusts options.
442         /// This options overwrites any previously set custom flags.
443         ///
444         /// # Examples
445         ///
446         /// ```no_run
447         /// use libc;
448         /// use tokio::fs::OpenOptions;
449         /// use std::io;
450         ///
451         /// #[tokio::main]
452         /// async fn main() -> io::Result<()> {
453         ///     let mut options = OpenOptions::new();
454         ///     options.write(true);
455         ///     if cfg!(unix) {
456         ///         options.custom_flags(libc::O_NOFOLLOW);
457         ///     }
458         ///     let file = options.open("foo.txt").await?;
459         ///
460         ///     Ok(())
461         /// }
462         /// ```
463         pub fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
464             self.as_inner_mut().custom_flags(flags);
465             self
466         }
467     }
468 }
469 
470 cfg_windows! {
471     impl OpenOptions {
472         /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
473         /// with the specified value.
474         ///
475         /// This will override the `read`, `write`, and `append` flags on the
476         /// `OpenOptions` structure. This method provides fine-grained control over
477         /// the permissions to read, write and append data, attributes (like hidden
478         /// and system), and extended attributes.
479         ///
480         /// # Examples
481         ///
482         /// ```no_run
483         /// use tokio::fs::OpenOptions;
484         ///
485         /// # #[tokio::main]
486         /// # async fn main() -> std::io::Result<()> {
487         /// // Open without read and write permission, for example if you only need
488         /// // to call `stat` on the file
489         /// let file = OpenOptions::new().access_mode(0).open("foo.txt").await?;
490         /// # Ok(())
491         /// # }
492         /// ```
493         ///
494         /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
495         pub fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
496             self.as_inner_mut().access_mode(access);
497             self
498         }
499 
500         /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with
501         /// the specified value.
502         ///
503         /// By default `share_mode` is set to
504         /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows
505         /// other processes to read, write, and delete/rename the same file
506         /// while it is open. Removing any of the flags will prevent other
507         /// processes from performing the corresponding operation until the file
508         /// handle is closed.
509         ///
510         /// # Examples
511         ///
512         /// ```no_run
513         /// use tokio::fs::OpenOptions;
514         ///
515         /// # #[tokio::main]
516         /// # async fn main() -> std::io::Result<()> {
517         /// // Do not allow others to read or modify this file while we have it open
518         /// // for writing.
519         /// let file = OpenOptions::new()
520         ///     .write(true)
521         ///     .share_mode(0)
522         ///     .open("foo.txt").await?;
523         /// # Ok(())
524         /// # }
525         /// ```
526         ///
527         /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
528         pub fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
529             self.as_inner_mut().share_mode(share);
530             self
531         }
532 
533         /// Sets extra flags for the `dwFileFlags` argument to the call to
534         /// [`CreateFile2`] to the specified value (or combines it with
535         /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes`
536         /// for [`CreateFile`]).
537         ///
538         /// Custom flags can only set flags, not remove flags set by Rust's options.
539         /// This option overwrites any previously set custom flags.
540         ///
541         /// # Examples
542         ///
543         /// ```no_run
544         /// use windows_sys::Win32::Storage::FileSystem::FILE_FLAG_DELETE_ON_CLOSE;
545         /// use tokio::fs::OpenOptions;
546         ///
547         /// # #[tokio::main]
548         /// # async fn main() -> std::io::Result<()> {
549         /// let file = OpenOptions::new()
550         ///     .create(true)
551         ///     .write(true)
552         ///     .custom_flags(FILE_FLAG_DELETE_ON_CLOSE)
553         ///     .open("foo.txt").await?;
554         /// # Ok(())
555         /// # }
556         /// ```
557         ///
558         /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
559         /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
560         pub fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
561             self.as_inner_mut().custom_flags(flags);
562             self
563         }
564 
565         /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to
566         /// the specified value (or combines it with `custom_flags` and
567         /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
568         /// [`CreateFile`]).
569         ///
570         /// If a _new_ file is created because it does not yet exist and
571         /// `.create(true)` or `.create_new(true)` are specified, the new file is
572         /// given the attributes declared with `.attributes()`.
573         ///
574         /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
575         /// existing attributes are preserved and combined with the ones declared
576         /// with `.attributes()`.
577         ///
578         /// In all other cases the attributes get ignored.
579         ///
580         /// # Examples
581         ///
582         /// ```no_run
583         /// use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_HIDDEN;
584         /// use tokio::fs::OpenOptions;
585         ///
586         /// # #[tokio::main]
587         /// # async fn main() -> std::io::Result<()> {
588         /// let file = OpenOptions::new()
589         ///     .write(true)
590         ///     .create(true)
591         ///     .attributes(FILE_ATTRIBUTE_HIDDEN)
592         ///     .open("foo.txt").await?;
593         /// # Ok(())
594         /// # }
595         /// ```
596         ///
597         /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
598         /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
599         pub fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
600             self.as_inner_mut().attributes(attributes);
601             self
602         }
603 
604         /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to
605         /// the specified value (or combines it with `custom_flags` and `attributes`
606         /// to set the `dwFlagsAndAttributes` for [`CreateFile`]).
607         ///
608         /// By default `security_qos_flags` is not set. It should be specified when
609         /// opening a named pipe, to control to which degree a server process can
610         /// act on behalf of a client process (security impersonation level).
611         ///
612         /// When `security_qos_flags` is not set, a malicious program can gain the
613         /// elevated privileges of a privileged Rust process when it allows opening
614         /// user-specified paths, by tricking it into opening a named pipe. So
615         /// arguably `security_qos_flags` should also be set when opening arbitrary
616         /// paths. However the bits can then conflict with other flags, specifically
617         /// `FILE_FLAG_OPEN_NO_RECALL`.
618         ///
619         /// For information about possible values, see [Impersonation Levels] on the
620         /// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set
621         /// automatically when using this method.
622         ///
623         /// # Examples
624         ///
625         /// ```no_run
626         /// use windows_sys::Win32::Storage::FileSystem::SECURITY_IDENTIFICATION;
627         /// use tokio::fs::OpenOptions;
628         ///
629         /// # #[tokio::main]
630         /// # async fn main() -> std::io::Result<()> {
631         /// let file = OpenOptions::new()
632         ///     .write(true)
633         ///     .create(true)
634         ///
635         ///     // Sets the flag value to `SecurityIdentification`.
636         ///     .security_qos_flags(SECURITY_IDENTIFICATION)
637         ///
638         ///     .open(r"\\.\pipe\MyPipe").await?;
639         /// # Ok(())
640         /// # }
641         /// ```
642         ///
643         /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
644         /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
645         /// [Impersonation Levels]:
646         ///     https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
647         pub fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
648             self.as_inner_mut().security_qos_flags(flags);
649             self
650         }
651     }
652 }
653 
654 impl From<StdOpenOptions> for OpenOptions {
from(options: StdOpenOptions) -> OpenOptions655     fn from(options: StdOpenOptions) -> OpenOptions {
656         OpenOptions(options)
657     }
658 }
659 
660 impl Default for OpenOptions {
default() -> Self661     fn default() -> Self {
662         Self::new()
663     }
664 }
665