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