Skip to main content

std/os/windows/
fs.rs

1//! Windows-specific extensions to primitives in the [`std::fs`] module.
2//!
3//! [`std::fs`]: crate::fs
4
5#![stable(feature = "rust1", since = "1.0.0")]
6
7use crate::fs::{self, Metadata, OpenOptions, Permissions};
8use crate::io::BorrowedCursor;
9use crate::macros::rustdoc_skip_body;
10use crate::path::Path;
11use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner};
12use crate::time::SystemTime;
13use crate::{io, sys};
14
15mod dirs;
16
17#[unstable(feature = "fs_home_dirs", issue = "162082")]
18pub use dirs::HomeDirsExt;
19#[unstable(feature = "fs_media_dirs", issue = "162083")]
20pub use dirs::MediaDirsExt;
21
22/// Windows-specific extensions to [`fs::File`].
23#[stable(feature = "file_offset", since = "1.15.0")]
24pub trait FileExt {
25    /// Seeks to a given position and reads a number of bytes.
26    ///
27    /// Returns the number of bytes read.
28    ///
29    /// The offset is relative to the start of the file and thus independent
30    /// from the current cursor. The current cursor **is** affected by this
31    /// function, it is set to the end of the read.
32    ///
33    /// Reading beyond the end of the file will always return with a length of
34    /// 0\.
35    ///
36    /// Note that similar to `File::read`, it is not an error to return with a
37    /// short read. When returning from such a short read, the file pointer is
38    /// still updated.
39    ///
40    /// # Examples
41    ///
42    #[cfg_attr(windows, doc = "```no_run")]
43    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
44    /// use std::io;
45    /// use std::fs::File;
46    /// use std::os::windows::prelude::*;
47    ///
48    /// fn main() -> io::Result<()> {
49    ///     let mut file = File::open("foo.txt")?;
50    ///     let mut buffer = [0; 10];
51    ///
52    ///     // Read 10 bytes, starting 72 bytes from the
53    ///     // start of the file.
54    ///     file.seek_read(&mut buffer[..], 72)?;
55    ///     Ok(())
56    /// }
57    /// ```
58    #[stable(feature = "file_offset", since = "1.15.0")]
59    fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
60
61    /// Seeks to a given position and reads the exact number of bytes required to fill `buf`.
62    ///
63    /// The offset is relative to the start of the file and thus independent
64    /// from the current cursor. The current cursor **is** affected by this
65    /// function, it is set to the end of the read.
66    ///
67    /// Similar to [`io::Read::read_exact`] but uses [`seek_read`] instead of `read`.
68    ///
69    /// [`seek_read`]: FileExt::seek_read
70    ///
71    /// # Errors
72    ///
73    ///
74    /// If this function encounters an "end of file" before completely filling
75    /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
76    /// The contents of `buf` are unspecified in this case.
77    ///
78    /// If any other read error is encountered then this function immediately
79    /// returns. The contents of `buf` are unspecified in this case.
80    ///
81    /// If this function returns an error, it is unspecified how many bytes it
82    /// has read, but it will never read more than would be necessary to
83    /// completely fill the buffer.
84    ///
85    /// # Examples
86    ///
87    #[cfg_attr(windows, doc = "```no_run")]
88    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
89    /// #![feature(seek_read_exact_seek_write_all)]
90    ///
91    /// use std::io;
92    /// use std::fs::File;
93    /// use std::os::windows::prelude::*;
94    ///
95    /// fn main() -> io::Result<()> {
96    ///     let mut file = File::open("foo.txt")?;
97    ///     let mut buffer = [0; 10];
98    ///
99    ///     // Read 10 bytes, starting 72 bytes from the
100    ///     // start of the file.
101    ///     file.seek_read_exact(&mut buffer[..], 72)?;
102    ///     Ok(())
103    /// }
104    /// ```
105    #[unstable(feature = "seek_read_exact_seek_write_all", issue = "162868")]
106    fn seek_read_exact(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
107        while !buf.is_empty() {
108            match self.seek_read(buf, offset) {
109                Ok(0) => break,
110                Ok(n) => {
111                    buf = &mut buf[n..];
112                    offset += n as u64;
113                }
114                Err(e) => return Err(e),
115            }
116        }
117        if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
118    }
119
120    /// Seeks to a given position and reads some bytes into the buffer.
121    ///
122    /// This is equivalent to the [`seek_read`](FileExt::seek_read) method, except that it is passed
123    /// a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with uninitialized buffers. The
124    /// new data will be appended to any existing contents of `buf`.
125    ///
126    /// Reading beyond the end of the file will always succeed without reading any bytes.
127    ///
128    /// # Examples
129    ///
130    #[cfg_attr(windows, doc = "```no_run")]
131    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
132    /// #![feature(core_io_borrowed_buf)]
133    /// #![feature(read_buf_at)]
134    ///
135    /// use std::io;
136    /// use std::io::BorrowedBuf;
137    /// use std::fs::File;
138    /// use std::mem::MaybeUninit;
139    /// use std::os::windows::prelude::*;
140    ///
141    /// fn main() -> io::Result<()> {
142    ///     let mut file = File::open("pi.txt")?;
143    ///
144    ///     // Read some bytes starting from offset 2
145    ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
146    ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice());
147    ///     file.seek_read_buf(buf.unfilled(), 2)?;
148    ///
149    ///     assert!(buf.filled().starts_with(b"1"));
150    ///
151    ///     Ok(())
152    /// }
153    /// ```
154    #[unstable(feature = "read_buf_at", issue = "140771")]
155    fn seek_read_buf(&self, buf: BorrowedCursor<'_, u8>, offset: u64) -> io::Result<()> {
156        io::default_read_buf(|b| self.seek_read(b, offset), buf)
157    }
158
159    /// Seeks to a given position and reads the exact number of bytes required to fill `buf`.
160    ///
161    /// This is equivalent to the [`seek_read_exact`](FileExt::seek_read_exact) method, except
162    /// that it is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with
163    /// uninitialized buffers. The new data will be appended to any existing contents of `buf`.
164    ///
165    /// Reading beyond the end of the file will always succeed without reading any bytes.
166    ///
167    /// # Examples
168    ///
169    #[cfg_attr(windows, doc = "```no_run")]
170    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
171    /// #![feature(core_io_borrowed_buf)]
172    /// #![feature(seek_read_exact_seek_write_all)]
173    ///
174    /// use std::io;
175    /// use std::io::BorrowedBuf;
176    /// use std::fs::File;
177    /// use std::mem::MaybeUninit;
178    /// use std::os::windows::prelude::*;
179    ///
180    /// fn main() -> io::Result<()> {
181    ///     let mut file = File::open("pi.txt")?;
182    ///
183    ///     // Read some bytes starting from offset 2
184    ///     let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
185    ///     let mut buf = BorrowedBuf::from(buf.as_mut_slice());
186    ///     file.seek_read_buf_exact(buf.unfilled(), 2)?;
187    ///
188    ///     assert!(buf.filled().starts_with(b"1"));
189    ///
190    ///     Ok(())
191    /// }
192    /// ```
193    #[unstable(feature = "seek_read_exact_seek_write_all", issue = "162868")]
194    fn seek_read_buf_exact(
195        &self,
196        mut buf: BorrowedCursor<'_, u8>,
197        mut offset: u64,
198    ) -> io::Result<()> {
199        while buf.capacity() > 0 {
200            let prev_written = buf.written();
201            match self.seek_read_buf(buf.reborrow(), offset) {
202                Ok(()) => {}
203                Err(e) => return Err(e),
204            }
205            let n = buf.written() - prev_written;
206            offset += n as u64;
207            if n == 0 {
208                return Err(io::Error::READ_EXACT_EOF);
209            }
210        }
211        Ok(())
212    }
213
214    /// Seeks to a given position and writes a number of bytes.
215    ///
216    /// Returns the number of bytes written.
217    ///
218    /// The offset is relative to the start of the file and thus independent
219    /// from the current cursor. The current cursor **is** affected by this
220    /// function, it is set to the end of the write.
221    ///
222    /// When writing beyond the end of the file, the file is appropriately
223    /// extended and the intermediate bytes are set to zero.
224    ///
225    /// Note that similar to `File::write`, it is not an error to return a
226    /// short write. When returning from such a short write, the file pointer
227    /// is still updated.
228    ///
229    /// # Examples
230    ///
231    #[cfg_attr(windows, doc = "```no_run")]
232    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
233    /// use std::fs::File;
234    /// use std::os::windows::prelude::*;
235    ///
236    /// fn main() -> std::io::Result<()> {
237    ///     let mut buffer = File::create("foo.txt")?;
238    ///
239    ///     // Write a byte string starting 72 bytes from
240    ///     // the start of the file.
241    ///     buffer.seek_write(b"some bytes", 72)?;
242    ///     Ok(())
243    /// }
244    /// ```
245    #[stable(feature = "file_offset", since = "1.15.0")]
246    fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
247
248    /// Seeks to a given position and attempts to write an entire buffer.
249    ///
250    /// The offset is relative to the start of the file and thus independent
251    /// from the current cursor. The current cursor **is** affected by this
252    /// function, it is set to the end of the write.
253    ///
254    /// This method will continuously call [`seek_write`] until there is no more data
255    /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
256    /// returned. This method will not return until the entire buffer has been
257    /// successfully written or such an error occurs. The first error that is
258    /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
259    /// returned.
260    ///
261    /// # Errors
262    ///
263    /// This function will return the first error that [`seek_write`] returns.
264    ///
265    /// [`seek_write`]: FileExt::seek_write
266    ///
267    /// # Examples
268    ///
269    #[cfg_attr(windows, doc = "```no_run")]
270    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
271    /// #![feature(seek_read_exact_seek_write_all)]
272    ///
273    /// use std::fs::File;
274    /// use std::os::windows::prelude::*;
275    ///
276    /// fn main() -> std::io::Result<()> {
277    ///     let mut buffer = File::create("foo.txt")?;
278    ///
279    ///     // Write a byte string starting 72 bytes from
280    ///     // the start of the file.
281    ///     buffer.seek_write_all(b"some bytes", 72)?;
282    ///     Ok(())
283    /// }
284    /// ```
285    #[unstable(feature = "seek_read_exact_seek_write_all", issue = "162868")]
286    fn seek_write_all(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
287        while !buf.is_empty() {
288            match self.seek_write(buf, offset) {
289                Ok(0) => {
290                    return Err(io::Error::WRITE_ALL_EOF);
291                }
292                Ok(n) => {
293                    buf = &buf[n..];
294                    offset += n as u64
295                }
296                Err(e) => return Err(e),
297            }
298        }
299        Ok(())
300    }
301}
302
303#[stable(feature = "file_offset", since = "1.15.0")]
304impl FileExt for fs::File {
305    fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
306        self.as_inner().read_at(buf, offset)
307    }
308
309    fn seek_read_buf(&self, buf: BorrowedCursor<'_, u8>, offset: u64) -> io::Result<()> {
310        self.as_inner().read_buf_at(buf, offset)
311    }
312
313    fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
314        self.as_inner().write_at(buf, offset)
315    }
316}
317
318/// Windows-specific extensions to [`fs::OpenOptions`].
319// WARNING: This trait is not sealed. DON'T add any new methods!
320// Add them to OpenOptionsExt2 instead.
321#[stable(feature = "open_options_ext", since = "1.10.0")]
322pub trait OpenOptionsExt {
323    /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
324    /// with the specified value.
325    ///
326    /// This will override the `read`, `write`, and `append` flags on the
327    /// `OpenOptions` structure. This method provides fine-grained control over
328    /// the permissions to read, write and append data, attributes (like hidden
329    /// and system), and extended attributes.
330    ///
331    /// # Examples
332    ///
333    #[cfg_attr(windows, doc = "```no_run")]
334    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
335    /// use std::fs::OpenOptions;
336    /// use std::os::windows::prelude::*;
337    ///
338    /// // Open without read and write permission, for example if you only need
339    /// // to call `stat` on the file
340    /// let file = OpenOptions::new().access_mode(0).open("foo.txt");
341    /// ```
342    ///
343    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
344    #[stable(feature = "open_options_ext", since = "1.10.0")]
345    fn access_mode(&mut self, access: u32) -> &mut Self;
346
347    /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with
348    /// the specified value.
349    ///
350    /// By default `share_mode` is set to
351    /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows
352    /// other processes to read, write, and delete/rename the same file
353    /// while it is open. Removing any of the flags will prevent other
354    /// processes from performing the corresponding operation until the file
355    /// handle is closed.
356    ///
357    /// # Examples
358    ///
359    #[cfg_attr(windows, doc = "```no_run")]
360    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
361    /// use std::fs::OpenOptions;
362    /// use std::os::windows::prelude::*;
363    ///
364    /// // Do not allow others to read or modify this file while we have it open
365    /// // for writing.
366    /// let file = OpenOptions::new()
367    ///     .write(true)
368    ///     .share_mode(0)
369    ///     .open("foo.txt");
370    /// ```
371    ///
372    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
373    #[stable(feature = "open_options_ext", since = "1.10.0")]
374    fn share_mode(&mut self, val: u32) -> &mut Self;
375
376    /// Sets extra flags for the `dwFileFlags` argument to the call to
377    /// [`CreateFile2`] to the specified value (or combines it with
378    /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes`
379    /// for [`CreateFile`]).
380    ///
381    /// Custom flags can only set flags, not remove flags set by Rust's options.
382    /// This option overwrites any previously set custom flags.
383    ///
384    /// # Examples
385    ///
386    #[cfg_attr(windows, doc = "```no_run")]
387    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
388    /// # #![allow(unexpected_cfgs)]
389    /// # #[cfg(for_demonstration_only)]
390    /// extern crate winapi;
391    /// # mod winapi { pub const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; }
392    ///
393    /// use std::fs::OpenOptions;
394    /// use std::os::windows::prelude::*;
395    ///
396    /// let file = OpenOptions::new()
397    ///     .create(true)
398    ///     .write(true)
399    ///     .custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE)
400    ///     .open("foo.txt");
401    /// ```
402    ///
403    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
404    /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
405    #[stable(feature = "open_options_ext", since = "1.10.0")]
406    fn custom_flags(&mut self, flags: u32) -> &mut Self;
407
408    /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to
409    /// the specified value (or combines it with `custom_flags` and
410    /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
411    /// [`CreateFile`]).
412    ///
413    /// If a _new_ file is created because it does not yet exist and
414    /// `.create(true)` or `.create_new(true)` are specified, the new file is
415    /// given the attributes declared with `.attributes()`.
416    ///
417    /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
418    /// existing attributes are preserved and combined with the ones declared
419    /// with `.attributes()`.
420    ///
421    /// In all other cases the attributes get ignored.
422    ///
423    /// # Examples
424    ///
425    #[cfg_attr(windows, doc = "```no_run")]
426    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
427    /// # #![allow(unexpected_cfgs)]
428    /// # #[cfg(for_demonstration_only)]
429    /// extern crate winapi;
430    /// # mod winapi { pub const FILE_ATTRIBUTE_HIDDEN: u32 = 2; }
431    ///
432    /// use std::fs::OpenOptions;
433    /// use std::os::windows::prelude::*;
434    ///
435    /// let file = OpenOptions::new()
436    ///     .write(true)
437    ///     .create(true)
438    ///     .attributes(winapi::FILE_ATTRIBUTE_HIDDEN)
439    ///     .open("foo.txt");
440    /// ```
441    ///
442    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
443    /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
444    #[stable(feature = "open_options_ext", since = "1.10.0")]
445    fn attributes(&mut self, val: u32) -> &mut Self;
446
447    /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to
448    /// the specified value (or combines it with `custom_flags` and `attributes`
449    /// to set the `dwFlagsAndAttributes` for [`CreateFile`]).
450    ///
451    /// By default `security_qos_flags` is not set. It should be specified when
452    /// opening a named pipe, to control to which degree a server process can
453    /// act on behalf of a client process (security impersonation level).
454    ///
455    /// When `security_qos_flags` is not set, a malicious program can gain the
456    /// elevated privileges of a privileged Rust process when it allows opening
457    /// user-specified paths, by tricking it into opening a named pipe. So
458    /// arguably `security_qos_flags` should also be set when opening arbitrary
459    /// paths. However the bits can then conflict with other flags, specifically
460    /// `FILE_FLAG_OPEN_NO_RECALL`.
461    ///
462    /// For information about possible values, see [Impersonation Levels] on the
463    /// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set
464    /// automatically when using this method.
465    ///
466    /// # Examples
467    ///
468    #[cfg_attr(windows, doc = "```no_run")]
469    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
470    /// # #![allow(unexpected_cfgs)]
471    /// # #[cfg(for_demonstration_only)]
472    /// extern crate winapi;
473    /// # mod winapi { pub const SECURITY_IDENTIFICATION: u32 = 0; }
474    /// use std::fs::OpenOptions;
475    /// use std::os::windows::prelude::*;
476    ///
477    /// let file = OpenOptions::new()
478    ///     .write(true)
479    ///     .create(true)
480    ///
481    ///     // Sets the flag value to `SecurityIdentification`.
482    ///     .security_qos_flags(winapi::SECURITY_IDENTIFICATION)
483    ///
484    ///     .open(r"\\.\pipe\MyPipe");
485    /// ```
486    ///
487    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
488    /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
489    /// [Impersonation Levels]:
490    ///     https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
491    #[stable(feature = "open_options_ext", since = "1.10.0")]
492    fn security_qos_flags(&mut self, flags: u32) -> &mut Self;
493}
494
495#[stable(feature = "open_options_ext", since = "1.10.0")]
496impl OpenOptionsExt for OpenOptions {
497    #[rustdoc_skip_body]
498    fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
499        self.as_inner_mut().access_mode(access);
500        self
501    }
502
503    #[rustdoc_skip_body]
504    fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
505        self.as_inner_mut().share_mode(share);
506        self
507    }
508
509    #[rustdoc_skip_body]
510    fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
511        self.as_inner_mut().custom_flags(flags);
512        self
513    }
514
515    #[rustdoc_skip_body]
516    fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
517        self.as_inner_mut().attributes(attributes);
518        self
519    }
520
521    #[rustdoc_skip_body]
522    fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
523        self.as_inner_mut().security_qos_flags(flags);
524        self
525    }
526}
527
528#[unstable(feature = "windows_freeze_file_times", issue = "149715")]
529pub impl(self) trait OpenOptionsExt2 {
530    /// If set to `true`, prevent the "last access time" of the file from being changed.
531    ///
532    /// Default to `false`.
533    #[unstable(feature = "windows_freeze_file_times", issue = "149715")]
534    fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self;
535
536    /// If set to `true`, prevent the "last write time" of the file from being changed.
537    ///
538    /// Default to `false`.
539    #[unstable(feature = "windows_freeze_file_times", issue = "149715")]
540    fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self;
541}
542
543#[unstable(feature = "windows_freeze_file_times", issue = "149715")]
544impl OpenOptionsExt2 for OpenOptions {
545    #[rustdoc_skip_body]
546    fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self {
547        self.as_inner_mut().freeze_last_access_time(freeze);
548        self
549    }
550
551    #[rustdoc_skip_body]
552    fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self {
553        self.as_inner_mut().freeze_last_write_time(freeze);
554        self
555    }
556}
557
558/// Windows-specific extensions to [`fs::Permissions`]. This extension trait
559/// provides extra utilities to shows what Windows file attributes are enabled
560/// in [`Permissions`] and to manually set file attributes on [`Permissions`].
561///
562/// See Microsoft's [`File Attribute Constants`] page to know what file
563/// attribute metadata are defined and stored on Windows files.
564///
565/// [`Permissions`]: fs::Permissions
566/// [`File Attribute Constants`]:
567///     https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
568///
569/// # Example
570///
571#[cfg_attr(windows, doc = "```no_run")]
572#[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
573/// #![feature(windows_permissions_ext)]
574/// use std::fs::Permissions;
575/// use std::os::windows::fs::PermissionsExt;
576///
577/// const FILE_ATTRIBUTE_SYSTEM: u32 = 0x4;
578/// const FILE_ATTRIBUTE_ARCHIVE: u32 = 0x20;
579/// let my_file_attr = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE;
580/// let mut permissions = Permissions::from_file_attributes(my_file_attr);
581/// assert_eq!(permissions.file_attributes(), my_file_attr);
582///
583/// const FILE_ATTRIBUTE_HIDDEN: u32 = 0x2;
584/// let new_file_attr = permissions.file_attributes() | FILE_ATTRIBUTE_HIDDEN;
585/// permissions.set_file_attributes(new_file_attr);
586/// assert_eq!(permissions.file_attributes(), new_file_attr);
587/// ```
588#[unstable(feature = "windows_permissions_ext", issue = "152956")]
589pub impl(self) trait PermissionsExt {
590    /// Returns the file attribute bits.
591    #[unstable(feature = "windows_permissions_ext", issue = "152956")]
592    fn file_attributes(&self) -> u32;
593
594    /// Sets the file attribute bits.
595    #[unstable(feature = "windows_permissions_ext", issue = "152956")]
596    fn set_file_attributes(&mut self, mask: u32);
597
598    /// Creates a new instance from the given file attribute bits.
599    #[unstable(feature = "windows_permissions_ext", issue = "152956")]
600    fn from_file_attributes(mask: u32) -> Self;
601}
602
603#[unstable(feature = "windows_permissions_ext", issue = "152956")]
604impl PermissionsExt for fs::Permissions {
605    #[rustdoc_skip_body]
606    fn file_attributes(&self) -> u32 {
607        self.as_inner().file_attributes()
608    }
609
610    fn set_file_attributes(&mut self, mask: u32) {
611        *self = Permissions::from_inner(FromInner::from_inner(mask));
612    }
613
614    fn from_file_attributes(mask: u32) -> Self {
615        Permissions::from_inner(FromInner::from_inner(mask))
616    }
617}
618
619/// Windows-specific extensions to [`fs::Metadata`].
620///
621/// The data members that this trait exposes correspond to the members
622/// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
623///
624/// [`BY_HANDLE_FILE_INFORMATION`]:
625///     https://docs.microsoft.com/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
626#[stable(feature = "metadata_ext", since = "1.1.0")]
627pub trait MetadataExt {
628    /// Returns the value of the `dwFileAttributes` field of this metadata.
629    ///
630    /// This field contains the file system attribute information for a file
631    /// or directory. For possible values and their descriptions, see
632    /// [File Attribute Constants] in the Windows Dev Center.
633    ///
634    /// # Examples
635    ///
636    #[cfg_attr(windows, doc = "```no_run")]
637    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
638    /// use std::io;
639    /// use std::fs;
640    /// use std::os::windows::prelude::*;
641    ///
642    /// fn main() -> io::Result<()> {
643    ///     let metadata = fs::metadata("foo.txt")?;
644    ///     let attributes = metadata.file_attributes();
645    ///     Ok(())
646    /// }
647    /// ```
648    ///
649    /// [File Attribute Constants]:
650    ///     https://docs.microsoft.com/windows/win32/fileio/file-attribute-constants
651    #[stable(feature = "metadata_ext", since = "1.1.0")]
652    fn file_attributes(&self) -> u32;
653
654    /// Returns the value of the `ftCreationTime` field of this metadata.
655    ///
656    /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
657    /// which represents the number of 100-nanosecond intervals since
658    /// January 1, 1601 (UTC). The struct is automatically
659    /// converted to a `u64` value, as that is the recommended way
660    /// to use it.
661    ///
662    /// If the underlying filesystem does not support creation time, the
663    /// returned value is 0.
664    ///
665    /// # Examples
666    ///
667    #[cfg_attr(windows, doc = "```no_run")]
668    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
669    /// use std::io;
670    /// use std::fs;
671    /// use std::os::windows::prelude::*;
672    ///
673    /// fn main() -> io::Result<()> {
674    ///     let metadata = fs::metadata("foo.txt")?;
675    ///     let creation_time = metadata.creation_time();
676    ///     Ok(())
677    /// }
678    /// ```
679    ///
680    /// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime
681    #[stable(feature = "metadata_ext", since = "1.1.0")]
682    fn creation_time(&self) -> u64;
683
684    /// Returns the value of the `ftLastAccessTime` field of this metadata.
685    ///
686    /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
687    /// which represents the number of 100-nanosecond intervals since
688    /// January 1, 1601 (UTC). The struct is automatically
689    /// converted to a `u64` value, as that is the recommended way
690    /// to use it.
691    ///
692    /// For a file, the value specifies the last time that a file was read
693    /// from or written to. For a directory, the value specifies when
694    /// the directory was created. For both files and directories, the
695    /// specified date is correct, but the time of day is always set to
696    /// midnight.
697    ///
698    /// If the underlying filesystem does not support last access time, the
699    /// returned value is 0.
700    ///
701    /// # Examples
702    ///
703    #[cfg_attr(windows, doc = "```no_run")]
704    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
705    /// use std::io;
706    /// use std::fs;
707    /// use std::os::windows::prelude::*;
708    ///
709    /// fn main() -> io::Result<()> {
710    ///     let metadata = fs::metadata("foo.txt")?;
711    ///     let last_access_time = metadata.last_access_time();
712    ///     Ok(())
713    /// }
714    /// ```
715    ///
716    /// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime
717    #[stable(feature = "metadata_ext", since = "1.1.0")]
718    fn last_access_time(&self) -> u64;
719
720    /// Returns the value of the `ftLastWriteTime` field of this metadata.
721    ///
722    /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
723    /// which represents the number of 100-nanosecond intervals since
724    /// January 1, 1601 (UTC). The struct is automatically
725    /// converted to a `u64` value, as that is the recommended way
726    /// to use it.
727    ///
728    /// For a file, the value specifies the last time that a file was written
729    /// to. For a directory, the structure specifies when the directory was
730    /// created.
731    ///
732    /// If the underlying filesystem does not support the last write time,
733    /// the returned value is 0.
734    ///
735    /// # Examples
736    ///
737    #[cfg_attr(windows, doc = "```no_run")]
738    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
739    /// use std::io;
740    /// use std::fs;
741    /// use std::os::windows::prelude::*;
742    ///
743    /// fn main() -> io::Result<()> {
744    ///     let metadata = fs::metadata("foo.txt")?;
745    ///     let last_write_time = metadata.last_write_time();
746    ///     Ok(())
747    /// }
748    /// ```
749    ///
750    /// [`FILETIME`]: https://docs.microsoft.com/windows/win32/api/minwinbase/ns-minwinbase-filetime
751    #[stable(feature = "metadata_ext", since = "1.1.0")]
752    fn last_write_time(&self) -> u64;
753
754    /// Returns the value of the `nFileSize` fields of this
755    /// metadata.
756    ///
757    /// The returned value does not have meaning for directories.
758    ///
759    /// # Examples
760    ///
761    #[cfg_attr(windows, doc = "```no_run")]
762    #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
763    /// use std::io;
764    /// use std::fs;
765    /// use std::os::windows::prelude::*;
766    ///
767    /// fn main() -> io::Result<()> {
768    ///     let metadata = fs::metadata("foo.txt")?;
769    ///     let file_size = metadata.file_size();
770    ///     Ok(())
771    /// }
772    /// ```
773    #[stable(feature = "metadata_ext", since = "1.1.0")]
774    fn file_size(&self) -> u64;
775
776    /// Returns the value of the `dwVolumeSerialNumber` field of this
777    /// metadata.
778    ///
779    /// This will return `None` if the `Metadata` instance was created from a
780    /// call to `DirEntry::metadata`. If this `Metadata` was created by using
781    /// `fs::metadata` or `File::metadata`, then this will return `Some`.
782    #[unstable(feature = "windows_by_handle", issue = "63010")]
783    fn volume_serial_number(&self) -> Option<u32>;
784
785    /// Returns the value of the `nNumberOfLinks` field of this
786    /// metadata.
787    ///
788    /// This will return `None` if the `Metadata` instance was created from a
789    /// call to `DirEntry::metadata`. If this `Metadata` was created by using
790    /// `fs::metadata` or `File::metadata`, then this will return `Some`.
791    #[unstable(feature = "windows_by_handle", issue = "63010")]
792    fn number_of_links(&self) -> Option<u32>;
793
794    /// Returns the value of the `nFileIndex` fields of this
795    /// metadata.
796    ///
797    /// This will return `None` if the `Metadata` instance was created from a
798    /// call to `DirEntry::metadata`. If this `Metadata` was created by using
799    /// `fs::metadata` or `File::metadata`, then this will return `Some`.
800    #[unstable(feature = "windows_by_handle", issue = "63010")]
801    fn file_index(&self) -> Option<u64>;
802
803    /// Returns the value of the `ChangeTime` fields of this metadata.
804    ///
805    /// `ChangeTime` is the last time file metadata was changed, such as
806    /// renames, attributes, etc.
807    ///
808    /// This will return `None` if `Metadata` instance was created from a call to
809    /// `DirEntry::metadata` or if the `target_vendor` is outside the current platform
810    /// support for this api.
811    #[unstable(feature = "windows_change_time", issue = "121478")]
812    fn change_time(&self) -> Option<u64>;
813}
814
815#[stable(feature = "metadata_ext", since = "1.1.0")]
816impl MetadataExt for Metadata {
817    #[rustdoc_skip_body]
818    fn file_attributes(&self) -> u32 {
819        self.as_inner().attrs()
820    }
821    #[rustdoc_skip_body]
822    fn creation_time(&self) -> u64 {
823        self.as_inner().created_u64()
824    }
825    #[rustdoc_skip_body]
826    fn last_access_time(&self) -> u64 {
827        self.as_inner().accessed_u64()
828    }
829    #[rustdoc_skip_body]
830    fn last_write_time(&self) -> u64 {
831        self.as_inner().modified_u64()
832    }
833    #[rustdoc_skip_body]
834    fn file_size(&self) -> u64 {
835        self.as_inner().size()
836    }
837    #[rustdoc_skip_body]
838    fn volume_serial_number(&self) -> Option<u32> {
839        self.as_inner().volume_serial_number()
840    }
841    #[rustdoc_skip_body]
842    fn number_of_links(&self) -> Option<u32> {
843        self.as_inner().number_of_links()
844    }
845    #[rustdoc_skip_body]
846    fn file_index(&self) -> Option<u64> {
847        self.as_inner().file_index()
848    }
849    #[rustdoc_skip_body]
850    fn change_time(&self) -> Option<u64> {
851        self.as_inner().changed_u64()
852    }
853}
854
855/// Windows-specific extensions to [`fs::FileType`].
856///
857/// On Windows, a symbolic link knows whether it is a file or directory.
858#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
859pub impl(self) trait FileTypeExt {
860    /// Returns `true` if this file type is a symbolic link that is also a directory.
861    #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
862    fn is_symlink_dir(&self) -> bool;
863    /// Returns `true` if this file type is a symbolic link that is also a file.
864    #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
865    fn is_symlink_file(&self) -> bool;
866}
867
868#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
869impl FileTypeExt for fs::FileType {
870    #[rustdoc_skip_body]
871    fn is_symlink_dir(&self) -> bool {
872        self.as_inner().is_symlink_dir()
873    }
874    #[rustdoc_skip_body]
875    fn is_symlink_file(&self) -> bool {
876        self.as_inner().is_symlink_file()
877    }
878}
879
880/// Windows-specific extensions to [`fs::FileTimes`].
881#[stable(feature = "file_set_times", since = "1.75.0")]
882pub impl(self) trait FileTimesExt {
883    /// Set the creation time of a file.
884    #[stable(feature = "file_set_times", since = "1.75.0")]
885    fn set_created(self, t: SystemTime) -> Self;
886}
887
888#[stable(feature = "file_set_times", since = "1.75.0")]
889impl FileTimesExt for fs::FileTimes {
890    #[rustdoc_skip_body]
891    fn set_created(mut self, t: SystemTime) -> Self {
892        self.as_inner_mut().set_created(t.into_inner());
893        self
894    }
895}
896
897/// Creates a new symlink to a non-directory file on the filesystem.
898///
899/// The `link` path will be a file symbolic link pointing to the `original`
900/// path.
901///
902/// The `original` path should not be a directory or a symlink to a directory,
903/// otherwise the symlink will be broken. Use [`symlink_dir`] for directories.
904///
905/// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW].
906/// Note that this [may change in the future][changes].
907///
908/// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
909/// [changes]: io#platform-specific-behavior
910///
911/// # Examples
912///
913#[cfg_attr(windows, doc = "```no_run")]
914#[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
915/// use std::os::windows::fs;
916///
917/// fn main() -> std::io::Result<()> {
918///     fs::symlink_file("a.txt", "b.txt")?;
919///     Ok(())
920/// }
921/// ```
922///
923/// # Limitations
924///
925/// Windows treats symlink creation as a [privileged action][symlink-security],
926/// therefore this function is likely to fail unless the user makes changes to
927/// their system to permit symlink creation. Users can try enabling Developer
928/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
929/// the process as an administrator.
930///
931/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
932#[doc(alias = "CreateSymbolicLink", alias = "CreateSymbolicLinkW")]
933#[stable(feature = "symlink", since = "1.1.0")]
934#[cfg_attr(not(test), rustc_diagnostic_item = "fs_symlink_file")]
935#[rustdoc_skip_body]
936pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
937    sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
938}
939
940/// Creates a new symlink to a directory on the filesystem.
941///
942/// The `link` path will be a directory symbolic link pointing to the `original`
943/// path.
944///
945/// The `original` path must be a directory or a symlink to a directory,
946/// otherwise the symlink will be broken. Use [`symlink_file`] for other files.
947///
948/// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW].
949/// Note that this [may change in the future][changes].
950///
951/// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
952/// [changes]: io#platform-specific-behavior
953///
954/// # Examples
955///
956#[cfg_attr(windows, doc = "```no_run")]
957#[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
958/// use std::os::windows::fs;
959///
960/// fn main() -> std::io::Result<()> {
961///     fs::symlink_dir("a", "b")?;
962///     Ok(())
963/// }
964/// ```
965///
966/// # Limitations
967///
968/// Windows treats symlink creation as a [privileged action][symlink-security],
969/// therefore this function is likely to fail unless the user makes changes to
970/// their system to permit symlink creation. Users can try enabling Developer
971/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
972/// the process as an administrator.
973///
974/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
975#[doc(alias = "CreateSymbolicLink", alias = "CreateSymbolicLinkW")]
976#[stable(feature = "symlink", since = "1.1.0")]
977#[cfg_attr(not(test), rustc_diagnostic_item = "fs_symlink_dir")]
978#[rustdoc_skip_body]
979pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
980    sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
981}
982
983/// Creates a junction point.
984///
985/// The `link` path will be a directory junction pointing to the original path.
986/// If `link` is a relative path then it will be made absolute prior to creating the junction point.
987/// The `original` path must be a directory or a link to a directory, otherwise the junction point will be broken.
988///
989/// If either path is not a local file path then this will fail.
990#[unstable(feature = "junction_point", issue = "121709")]
991#[rustdoc_skip_body]
992pub fn junction_point<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
993    sys::fs::junction_point(original.as_ref(), link.as_ref())
994}