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 reads the exact number of bytes required to fill `buf`.
156 ///
157 /// This is equivalent to the [`seek_read_exact`](FileExt::seek_read_exact) method, except
158 /// that it is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with
159 /// uninitialized buffers. The new data will be appended to any existing contents of `buf`.
160 ///
161 /// Reading beyond the end of the file will always succeed without reading any bytes.
162 ///
163 /// # Examples
164 ///
165 #[cfg_attr(windows, doc = "```no_run")]
166 #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
167 /// #![feature(core_io_borrowed_buf)]
168 /// #![feature(seek_read_exact_seek_write_all)]
169 ///
170 /// use std::io;
171 /// use std::io::BorrowedBuf;
172 /// use std::fs::File;
173 /// use std::mem::MaybeUninit;
174 /// use std::os::windows::prelude::*;
175 ///
176 /// fn main() -> io::Result<()> {
177 /// let mut file = File::open("pi.txt")?;
178 ///
179 /// // Read some bytes starting from offset 2
180 /// let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
181 /// let mut buf = BorrowedBuf::from(buf.as_mut_slice());
182 /// file.seek_read_buf_exact(buf.unfilled(), 2)?;
183 ///
184 /// assert!(buf.filled().starts_with(b"1"));
185 ///
186 /// Ok(())
187 /// }
188 /// ```
189 #[unstable(feature = "seek_read_exact_seek_write_all", issue = "162868")]
190 fn seek_read_buf_exact(
191 &self,
192 mut buf: BorrowedCursor<'_, u8>,
193 mut offset: u64,
194 ) -> io::Result<()> {
195 while buf.capacity() > 0 {
196 let prev_written = buf.written();
197 match self.seek_read_buf(buf.reborrow(), offset) {
198 Ok(()) => {}
199 Err(e) if e.is_interrupted() => {}
200 Err(e) => return Err(e),
201 }
202 let n = buf.written() - prev_written;
203 offset += n as u64;
204 if n == 0 {
205 return Err(io::Error::READ_EXACT_EOF);
206 }
207 }
208 Ok(())
209 }
210
211 /// Seeks to a given position and writes a number of bytes.
212 ///
213 /// Returns the number of bytes written.
214 ///
215 /// The offset is relative to the start of the file and thus independent
216 /// from the current cursor. The current cursor **is** affected by this
217 /// function, it is set to the end of the write.
218 ///
219 /// When writing beyond the end of the file, the file is appropriately
220 /// extended and the intermediate bytes are set to zero.
221 ///
222 /// Note that similar to `File::write`, it is not an error to return a
223 /// short write. When returning from such a short write, the file pointer
224 /// is still updated.
225 ///
226 /// # Examples
227 ///
228 #[cfg_attr(windows, doc = "```no_run")]
229 #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
230 /// use std::fs::File;
231 /// use std::os::windows::prelude::*;
232 ///
233 /// fn main() -> std::io::Result<()> {
234 /// let mut buffer = File::create("foo.txt")?;
235 ///
236 /// // Write a byte string starting 72 bytes from
237 /// // the start of the file.
238 /// buffer.seek_write(b"some bytes", 72)?;
239 /// Ok(())
240 /// }
241 /// ```
242 #[stable(feature = "file_offset", since = "1.15.0")]
243 fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
244
245 /// Seeks to a given position and attempts to write an entire buffer.
246 ///
247 /// The offset is relative to the start of the file and thus independent
248 /// from the current cursor. The current cursor **is** affected by this
249 /// function, it is set to the end of the write.
250 ///
251 /// This method will continuously call [`seek_write`] until there is no more data
252 /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
253 /// returned. This method will not return until the entire buffer has been
254 /// successfully written or such an error occurs. The first error that is
255 /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
256 /// returned.
257 ///
258 /// # Errors
259 ///
260 /// This function will return the first error of
261 /// non-[`io::ErrorKind::Interrupted`] kind that [`seek_write`] returns.
262 ///
263 /// [`seek_write`]: FileExt::seek_write
264 ///
265 /// # Examples
266 ///
267 #[cfg_attr(windows, doc = "```no_run")]
268 #[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
269 /// #![feature(seek_read_exact_seek_write_all)]
270 ///
271 /// use std::fs::File;
272 /// use std::os::windows::prelude::*;
273 ///
274 /// fn main() -> std::io::Result<()> {
275 /// let mut buffer = File::create("foo.txt")?;
276 ///
277 /// // Write a byte string starting 72 bytes from
278 /// // the start of the file.
279 /// buffer.seek_write_all(b"some bytes", 72)?;
280 /// Ok(())
281 /// }
282 /// ```
283 #[unstable(feature = "seek_read_exact_seek_write_all", issue = "162868")]
284 fn seek_write_all(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
285 while !buf.is_empty() {
286 match self.seek_write(buf, offset) {
287 Ok(0) => {
288 return Err(io::Error::WRITE_ALL_EOF);
289 }
290 Ok(n) => {
291 buf = &buf[n..];
292 offset += n as u64
293 }
294 Err(ref e) if e.is_interrupted() => {}
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#[stable(feature = "symlink", since = "1.1.0")]
912#[cfg_attr(not(test), rustc_diagnostic_item = "fs_symlink_file")]
913pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
914 sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
915}
916
917/// Creates a new symlink to a directory on the filesystem.
918///
919/// The `link` path will be a directory symbolic link pointing to the `original`
920/// path.
921///
922/// The `original` path must be a directory or a symlink to a directory,
923/// otherwise the symlink will be broken. Use [`symlink_file`] for other files.
924///
925/// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW].
926/// Note that this [may change in the future][changes].
927///
928/// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
929/// [changes]: io#platform-specific-behavior
930///
931/// # Examples
932///
933#[cfg_attr(windows, doc = "```no_run")]
934#[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
935/// use std::os::windows::fs;
936///
937/// fn main() -> std::io::Result<()> {
938/// fs::symlink_dir("a", "b")?;
939/// Ok(())
940/// }
941/// ```
942///
943/// # Limitations
944///
945/// Windows treats symlink creation as a [privileged action][symlink-security],
946/// therefore this function is likely to fail unless the user makes changes to
947/// their system to permit symlink creation. Users can try enabling Developer
948/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
949/// the process as an administrator.
950///
951/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
952#[stable(feature = "symlink", since = "1.1.0")]
953#[cfg_attr(not(test), rustc_diagnostic_item = "fs_symlink_dir")]
954pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
955 sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
956}
957
958/// Creates a junction point.
959///
960/// The `link` path will be a directory junction pointing to the original path.
961/// If `link` is a relative path then it will be made absolute prior to creating the junction point.
962/// The `original` path must be a directory or a link to a directory, otherwise the junction point will be broken.
963///
964/// If either path is not a local file path then this will fail.
965#[unstable(feature = "junction_point", issue = "121709")]
966pub fn junction_point<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
967 sys::fs::junction_point(original.as_ref(), link.as_ref())
968}