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