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