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