]> git.lizzy.rs Git - rust.git/blob - library/std/src/os/windows/fs.rs
Auto merge of #94517 - aDotInTheVoid:inline_wrapping_next_power_two, r=yaahc
[rust.git] / library / std / src / 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
7 use crate::fs::{self, Metadata, OpenOptions};
8 use crate::io;
9 use crate::path::Path;
10 use crate::sys;
11 use crate::sys_common::{AsInner, AsInnerMut};
12
13 /// Windows-specific extensions to [`fs::File`].
14 #[stable(feature = "file_offset", since = "1.15.0")]
15 pub trait FileExt {
16     /// Seeks to a given position and reads a number of bytes.
17     ///
18     /// Returns the number of bytes read.
19     ///
20     /// The offset is relative to the start of the file and thus independent
21     /// from the current cursor. The current cursor **is** affected by this
22     /// function, it is set to the end of the read.
23     ///
24     /// Reading beyond the end of the file will always return with a length of
25     /// 0\.
26     ///
27     /// Note that similar to `File::read`, it is not an error to return with a
28     /// short read. When returning from such a short read, the file pointer is
29     /// still updated.
30     ///
31     /// # Examples
32     ///
33     /// ```no_run
34     /// use std::io;
35     /// use std::fs::File;
36     /// use std::os::windows::prelude::*;
37     ///
38     /// fn main() -> io::Result<()> {
39     ///     let mut file = File::open("foo.txt")?;
40     ///     let mut buffer = [0; 10];
41     ///
42     ///     // Read 10 bytes, starting 72 bytes from the
43     ///     // start of the file.
44     ///     file.seek_read(&mut buffer[..], 72)?;
45     ///     Ok(())
46     /// }
47     /// ```
48     #[stable(feature = "file_offset", since = "1.15.0")]
49     fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
50
51     /// Seeks to a given position and writes a number of bytes.
52     ///
53     /// Returns the number of bytes written.
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 write.
58     ///
59     /// When writing beyond the end of the file, the file is appropriately
60     /// extended and the intermediate bytes are left uninitialized.
61     ///
62     /// Note that similar to `File::write`, it is not an error to return a
63     /// short write. When returning from such a short write, the file pointer
64     /// is still updated.
65     ///
66     /// # Examples
67     ///
68     /// ```no_run
69     /// use std::fs::File;
70     /// use std::os::windows::prelude::*;
71     ///
72     /// fn main() -> std::io::Result<()> {
73     ///     let mut buffer = File::create("foo.txt")?;
74     ///
75     ///     // Write a byte string starting 72 bytes from
76     ///     // the start of the file.
77     ///     buffer.seek_write(b"some bytes", 72)?;
78     ///     Ok(())
79     /// }
80     /// ```
81     #[stable(feature = "file_offset", since = "1.15.0")]
82     fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
83 }
84
85 #[stable(feature = "file_offset", since = "1.15.0")]
86 impl FileExt for fs::File {
87     fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
88         self.as_inner().read_at(buf, offset)
89     }
90
91     fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
92         self.as_inner().write_at(buf, offset)
93     }
94 }
95
96 /// Windows-specific extensions to [`fs::OpenOptions`].
97 #[stable(feature = "open_options_ext", since = "1.10.0")]
98 pub trait OpenOptionsExt {
99     /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
100     /// with the specified value.
101     ///
102     /// This will override the `read`, `write`, and `append` flags on the
103     /// `OpenOptions` structure. This method provides fine-grained control over
104     /// the permissions to read, write and append data, attributes (like hidden
105     /// and system), and extended attributes.
106     ///
107     /// # Examples
108     ///
109     /// ```no_run
110     /// use std::fs::OpenOptions;
111     /// use std::os::windows::prelude::*;
112     ///
113     /// // Open without read and write permission, for example if you only need
114     /// // to call `stat` on the file
115     /// let file = OpenOptions::new().access_mode(0).open("foo.txt");
116     /// ```
117     ///
118     /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
119     #[stable(feature = "open_options_ext", since = "1.10.0")]
120     fn access_mode(&mut self, access: u32) -> &mut Self;
121
122     /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with
123     /// the specified value.
124     ///
125     /// By default `share_mode` is set to
126     /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows
127     /// other processes to read, write, and delete/rename the same file
128     /// while it is open. Removing any of the flags will prevent other
129     /// processes from performing the corresponding operation until the file
130     /// handle is closed.
131     ///
132     /// # Examples
133     ///
134     /// ```no_run
135     /// use std::fs::OpenOptions;
136     /// use std::os::windows::prelude::*;
137     ///
138     /// // Do not allow others to read or modify this file while we have it open
139     /// // for writing.
140     /// let file = OpenOptions::new()
141     ///     .write(true)
142     ///     .share_mode(0)
143     ///     .open("foo.txt");
144     /// ```
145     ///
146     /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
147     #[stable(feature = "open_options_ext", since = "1.10.0")]
148     fn share_mode(&mut self, val: u32) -> &mut Self;
149
150     /// Sets extra flags for the `dwFileFlags` argument to the call to
151     /// [`CreateFile2`] to the specified value (or combines it with
152     /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes`
153     /// for [`CreateFile`]).
154     ///
155     /// Custom flags can only set flags, not remove flags set by Rust's options.
156     /// This option overwrites any previously set custom flags.
157     ///
158     /// # Examples
159     ///
160     /// ```no_run
161     /// # #![allow(unexpected_cfgs)]
162     /// # #[cfg(for_demonstration_only)]
163     /// extern crate winapi;
164     /// # mod winapi { pub const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; }
165     ///
166     /// use std::fs::OpenOptions;
167     /// use std::os::windows::prelude::*;
168     ///
169     /// let file = OpenOptions::new()
170     ///     .create(true)
171     ///     .write(true)
172     ///     .custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE)
173     ///     .open("foo.txt");
174     /// ```
175     ///
176     /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
177     /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
178     #[stable(feature = "open_options_ext", since = "1.10.0")]
179     fn custom_flags(&mut self, flags: u32) -> &mut Self;
180
181     /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to
182     /// the specified value (or combines it with `custom_flags` and
183     /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
184     /// [`CreateFile`]).
185     ///
186     /// If a _new_ file is created because it does not yet exist and
187     /// `.create(true)` or `.create_new(true)` are specified, the new file is
188     /// given the attributes declared with `.attributes()`.
189     ///
190     /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
191     /// existing attributes are preserved and combined with the ones declared
192     /// with `.attributes()`.
193     ///
194     /// In all other cases the attributes get ignored.
195     ///
196     /// # Examples
197     ///
198     /// ```no_run
199     /// # #![allow(unexpected_cfgs)]
200     /// # #[cfg(for_demonstration_only)]
201     /// extern crate winapi;
202     /// # mod winapi { pub const FILE_ATTRIBUTE_HIDDEN: u32 = 2; }
203     ///
204     /// use std::fs::OpenOptions;
205     /// use std::os::windows::prelude::*;
206     ///
207     /// let file = OpenOptions::new()
208     ///     .write(true)
209     ///     .create(true)
210     ///     .attributes(winapi::FILE_ATTRIBUTE_HIDDEN)
211     ///     .open("foo.txt");
212     /// ```
213     ///
214     /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
215     /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
216     #[stable(feature = "open_options_ext", since = "1.10.0")]
217     fn attributes(&mut self, val: u32) -> &mut Self;
218
219     /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to
220     /// the specified value (or combines it with `custom_flags` and `attributes`
221     /// to set the `dwFlagsAndAttributes` for [`CreateFile`]).
222     ///
223     /// By default `security_qos_flags` is not set. It should be specified when
224     /// opening a named pipe, to control to which degree a server process can
225     /// act on behalf of a client process (security impersonation level).
226     ///
227     /// When `security_qos_flags` is not set, a malicious program can gain the
228     /// elevated privileges of a privileged Rust process when it allows opening
229     /// user-specified paths, by tricking it into opening a named pipe. So
230     /// arguably `security_qos_flags` should also be set when opening arbitrary
231     /// paths. However the bits can then conflict with other flags, specifically
232     /// `FILE_FLAG_OPEN_NO_RECALL`.
233     ///
234     /// For information about possible values, see [Impersonation Levels] on the
235     /// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set
236     /// automatically when using this method.
237
238     /// # Examples
239     ///
240     /// ```no_run
241     /// # #![allow(unexpected_cfgs)]
242     /// # #[cfg(for_demonstration_only)]
243     /// extern crate winapi;
244     /// # mod winapi { pub const SECURITY_IDENTIFICATION: u32 = 0; }
245     /// use std::fs::OpenOptions;
246     /// use std::os::windows::prelude::*;
247     ///
248     /// let file = OpenOptions::new()
249     ///     .write(true)
250     ///     .create(true)
251     ///
252     ///     // Sets the flag value to `SecurityIdentification`.
253     ///     .security_qos_flags(winapi::SECURITY_IDENTIFICATION)
254     ///
255     ///     .open(r"\\.\pipe\MyPipe");
256     /// ```
257     ///
258     /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
259     /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
260     /// [Impersonation Levels]:
261     ///     https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
262     #[stable(feature = "open_options_ext", since = "1.10.0")]
263     fn security_qos_flags(&mut self, flags: u32) -> &mut Self;
264 }
265
266 #[stable(feature = "open_options_ext", since = "1.10.0")]
267 impl OpenOptionsExt for OpenOptions {
268     fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
269         self.as_inner_mut().access_mode(access);
270         self
271     }
272
273     fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
274         self.as_inner_mut().share_mode(share);
275         self
276     }
277
278     fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
279         self.as_inner_mut().custom_flags(flags);
280         self
281     }
282
283     fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
284         self.as_inner_mut().attributes(attributes);
285         self
286     }
287
288     fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
289         self.as_inner_mut().security_qos_flags(flags);
290         self
291     }
292 }
293
294 /// Windows-specific extensions to [`fs::Metadata`].
295 ///
296 /// The data members that this trait exposes correspond to the members
297 /// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
298 ///
299 /// [`BY_HANDLE_FILE_INFORMATION`]:
300 ///     https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
301 #[stable(feature = "metadata_ext", since = "1.1.0")]
302 pub trait MetadataExt {
303     /// Returns the value of the `dwFileAttributes` field of this metadata.
304     ///
305     /// This field contains the file system attribute information for a file
306     /// or directory. For possible values and their descriptions, see
307     /// [File Attribute Constants] in the Windows Dev Center.
308     ///
309     /// # Examples
310     ///
311     /// ```no_run
312     /// use std::io;
313     /// use std::fs;
314     /// use std::os::windows::prelude::*;
315     ///
316     /// fn main() -> io::Result<()> {
317     ///     let metadata = fs::metadata("foo.txt")?;
318     ///     let attributes = metadata.file_attributes();
319     ///     Ok(())
320     /// }
321     /// ```
322     ///
323     /// [File Attribute Constants]:
324     ///     https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
325     #[stable(feature = "metadata_ext", since = "1.1.0")]
326     fn file_attributes(&self) -> u32;
327
328     /// Returns the value of the `ftCreationTime` field of this metadata.
329     ///
330     /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
331     /// which represents the number of 100-nanosecond intervals since
332     /// January 1, 1601 (UTC). The struct is automatically
333     /// converted to a `u64` value, as that is the recommended way
334     /// to use it.
335     ///
336     /// If the underlying filesystem does not support creation time, the
337     /// returned value is 0.
338     ///
339     /// # Examples
340     ///
341     /// ```no_run
342     /// use std::io;
343     /// use std::fs;
344     /// use std::os::windows::prelude::*;
345     ///
346     /// fn main() -> io::Result<()> {
347     ///     let metadata = fs::metadata("foo.txt")?;
348     ///     let creation_time = metadata.creation_time();
349     ///     Ok(())
350     /// }
351     /// ```
352     ///
353     /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
354     #[stable(feature = "metadata_ext", since = "1.1.0")]
355     fn creation_time(&self) -> u64;
356
357     /// Returns the value of the `ftLastAccessTime` field of this metadata.
358     ///
359     /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
360     /// which represents the number of 100-nanosecond intervals since
361     /// January 1, 1601 (UTC). The struct is automatically
362     /// converted to a `u64` value, as that is the recommended way
363     /// to use it.
364     ///
365     /// For a file, the value specifies the last time that a file was read
366     /// from or written to. For a directory, the value specifies when
367     /// the directory was created. For both files and directories, the
368     /// specified date is correct, but the time of day is always set to
369     /// midnight.
370     ///
371     /// If the underlying filesystem does not support last access time, the
372     /// returned value is 0.
373     ///
374     /// # Examples
375     ///
376     /// ```no_run
377     /// use std::io;
378     /// use std::fs;
379     /// use std::os::windows::prelude::*;
380     ///
381     /// fn main() -> io::Result<()> {
382     ///     let metadata = fs::metadata("foo.txt")?;
383     ///     let last_access_time = metadata.last_access_time();
384     ///     Ok(())
385     /// }
386     /// ```
387     ///
388     /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
389     #[stable(feature = "metadata_ext", since = "1.1.0")]
390     fn last_access_time(&self) -> u64;
391
392     /// Returns the value of the `ftLastWriteTime` field of this metadata.
393     ///
394     /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
395     /// which represents the number of 100-nanosecond intervals since
396     /// January 1, 1601 (UTC). The struct is automatically
397     /// converted to a `u64` value, as that is the recommended way
398     /// to use it.
399     ///
400     /// For a file, the value specifies the last time that a file was written
401     /// to. For a directory, the structure specifies when the directory was
402     /// created.
403     ///
404     /// If the underlying filesystem does not support the last write time,
405     /// the returned value is 0.
406     ///
407     /// # Examples
408     ///
409     /// ```no_run
410     /// use std::io;
411     /// use std::fs;
412     /// use std::os::windows::prelude::*;
413     ///
414     /// fn main() -> io::Result<()> {
415     ///     let metadata = fs::metadata("foo.txt")?;
416     ///     let last_write_time = metadata.last_write_time();
417     ///     Ok(())
418     /// }
419     /// ```
420     ///
421     /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
422     #[stable(feature = "metadata_ext", since = "1.1.0")]
423     fn last_write_time(&self) -> u64;
424
425     /// Returns the value of the `nFileSize{High,Low}` fields of this
426     /// metadata.
427     ///
428     /// The returned value does not have meaning for directories.
429     ///
430     /// # Examples
431     ///
432     /// ```no_run
433     /// use std::io;
434     /// use std::fs;
435     /// use std::os::windows::prelude::*;
436     ///
437     /// fn main() -> io::Result<()> {
438     ///     let metadata = fs::metadata("foo.txt")?;
439     ///     let file_size = metadata.file_size();
440     ///     Ok(())
441     /// }
442     /// ```
443     #[stable(feature = "metadata_ext", since = "1.1.0")]
444     fn file_size(&self) -> u64;
445
446     /// Returns the value of the `dwVolumeSerialNumber` field of this
447     /// metadata.
448     ///
449     /// This will return `None` if the `Metadata` instance was created from a
450     /// call to `DirEntry::metadata`. If this `Metadata` was created by using
451     /// `fs::metadata` or `File::metadata`, then this will return `Some`.
452     #[unstable(feature = "windows_by_handle", issue = "63010")]
453     fn volume_serial_number(&self) -> Option<u32>;
454
455     /// Returns the value of the `nNumberOfLinks` field of this
456     /// metadata.
457     ///
458     /// This will return `None` if the `Metadata` instance was created from a
459     /// call to `DirEntry::metadata`. If this `Metadata` was created by using
460     /// `fs::metadata` or `File::metadata`, then this will return `Some`.
461     #[unstable(feature = "windows_by_handle", issue = "63010")]
462     fn number_of_links(&self) -> Option<u32>;
463
464     /// Returns the value of the `nFileIndex{Low,High}` fields of this
465     /// metadata.
466     ///
467     /// This will return `None` if the `Metadata` instance was created from a
468     /// call to `DirEntry::metadata`. If this `Metadata` was created by using
469     /// `fs::metadata` or `File::metadata`, then this will return `Some`.
470     #[unstable(feature = "windows_by_handle", issue = "63010")]
471     fn file_index(&self) -> Option<u64>;
472 }
473
474 #[stable(feature = "metadata_ext", since = "1.1.0")]
475 impl MetadataExt for Metadata {
476     fn file_attributes(&self) -> u32 {
477         self.as_inner().attrs()
478     }
479     fn creation_time(&self) -> u64 {
480         self.as_inner().created_u64()
481     }
482     fn last_access_time(&self) -> u64 {
483         self.as_inner().accessed_u64()
484     }
485     fn last_write_time(&self) -> u64 {
486         self.as_inner().modified_u64()
487     }
488     fn file_size(&self) -> u64 {
489         self.as_inner().size()
490     }
491     fn volume_serial_number(&self) -> Option<u32> {
492         self.as_inner().volume_serial_number()
493     }
494     fn number_of_links(&self) -> Option<u32> {
495         self.as_inner().number_of_links()
496     }
497     fn file_index(&self) -> Option<u64> {
498         self.as_inner().file_index()
499     }
500 }
501
502 /// Windows-specific extensions to [`fs::FileType`].
503 ///
504 /// On Windows, a symbolic link knows whether it is a file or directory.
505 #[unstable(feature = "windows_file_type_ext", issue = "none")]
506 pub trait FileTypeExt {
507     /// Returns `true` if this file type is a symbolic link that is also a directory.
508     #[unstable(feature = "windows_file_type_ext", issue = "none")]
509     fn is_symlink_dir(&self) -> bool;
510     /// Returns `true` if this file type is a symbolic link that is also a file.
511     #[unstable(feature = "windows_file_type_ext", issue = "none")]
512     fn is_symlink_file(&self) -> bool;
513 }
514
515 #[unstable(feature = "windows_file_type_ext", issue = "none")]
516 impl FileTypeExt for fs::FileType {
517     fn is_symlink_dir(&self) -> bool {
518         self.as_inner().is_symlink_dir()
519     }
520     fn is_symlink_file(&self) -> bool {
521         self.as_inner().is_symlink_file()
522     }
523 }
524
525 /// Creates a new symlink to a non-directory file on the filesystem.
526 ///
527 /// The `link` path will be a file symbolic link pointing to the `original`
528 /// path.
529 ///
530 /// The `original` path should not be a directory or a symlink to a directory,
531 /// otherwise the symlink will be broken. Use [`symlink_dir`] for directories.
532 ///
533 /// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW].
534 /// Note that this [may change in the future][changes].
535 ///
536 /// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
537 /// [changes]: io#platform-specific-behavior
538 ///
539 /// # Examples
540 ///
541 /// ```no_run
542 /// use std::os::windows::fs;
543 ///
544 /// fn main() -> std::io::Result<()> {
545 ///     fs::symlink_file("a.txt", "b.txt")?;
546 ///     Ok(())
547 /// }
548 /// ```
549 ///
550 /// # Limitations
551 ///
552 /// Windows treats symlink creation as a [privileged action][symlink-security],
553 /// therefore this function is likely to fail unless the user makes changes to
554 /// their system to permit symlink creation. Users can try enabling Developer
555 /// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
556 /// the process as an administrator.
557 ///
558 /// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
559 #[stable(feature = "symlink", since = "1.1.0")]
560 pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
561     sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
562 }
563
564 /// Creates a new symlink to a directory on the filesystem.
565 ///
566 /// The `link` path will be a directory symbolic link pointing to the `original`
567 /// path.
568 ///
569 /// The `original` path must be a directory or a symlink to a directory,
570 /// otherwise the symlink will be broken. Use [`symlink_file`] for other files.
571 ///
572 /// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW].
573 /// Note that this [may change in the future][changes].
574 ///
575 /// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
576 /// [changes]: io#platform-specific-behavior
577 ///
578 /// # Examples
579 ///
580 /// ```no_run
581 /// use std::os::windows::fs;
582 ///
583 /// fn main() -> std::io::Result<()> {
584 ///     fs::symlink_dir("a", "b")?;
585 ///     Ok(())
586 /// }
587 /// ```
588 ///
589 /// # Limitations
590 ///
591 /// Windows treats symlink creation as a [privileged action][symlink-security],
592 /// therefore this function is likely to fail unless the user makes changes to
593 /// their system to permit symlink creation. Users can try enabling Developer
594 /// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
595 /// the process as an administrator.
596 ///
597 /// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
598 #[stable(feature = "symlink", since = "1.1.0")]
599 pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
600     sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
601 }