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