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