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};
8use crate::path::Path;
9use crate::sealed::Sealed;
10use crate::sys_common::{AsInner, AsInnerMut, 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    /// ```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 set to zero.
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")]
87impl 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")]
99pub 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")]
268impl 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/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
302#[stable(feature = "metadata_ext", since = "1.1.0")]
303pub 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/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/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/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/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` 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` 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    /// Returns the value of the `ChangeTime` fields of this metadata.
475    ///
476    /// `ChangeTime` is the last time file metadata was changed, such as
477    /// renames, attributes, etc.
478    ///
479    /// This will return `None` if `Metadata` instance was created from a call to
480    /// `DirEntry::metadata` or if the `target_vendor` is outside the current platform
481    /// support for this api.
482    #[unstable(feature = "windows_change_time", issue = "121478")]
483    fn change_time(&self) -> Option<u64>;
484}
485
486#[stable(feature = "metadata_ext", since = "1.1.0")]
487impl MetadataExt for Metadata {
488    fn file_attributes(&self) -> u32 {
489        self.as_inner().attrs()
490    }
491    fn creation_time(&self) -> u64 {
492        self.as_inner().created_u64()
493    }
494    fn last_access_time(&self) -> u64 {
495        self.as_inner().accessed_u64()
496    }
497    fn last_write_time(&self) -> u64 {
498        self.as_inner().modified_u64()
499    }
500    fn file_size(&self) -> u64 {
501        self.as_inner().size()
502    }
503    fn volume_serial_number(&self) -> Option<u32> {
504        self.as_inner().volume_serial_number()
505    }
506    fn number_of_links(&self) -> Option<u32> {
507        self.as_inner().number_of_links()
508    }
509    fn file_index(&self) -> Option<u64> {
510        self.as_inner().file_index()
511    }
512    fn change_time(&self) -> Option<u64> {
513        self.as_inner().changed_u64()
514    }
515}
516
517/// Windows-specific extensions to [`fs::FileType`].
518///
519/// On Windows, a symbolic link knows whether it is a file or directory.
520#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
521pub trait FileTypeExt: Sealed {
522    /// Returns `true` if this file type is a symbolic link that is also a directory.
523    #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
524    fn is_symlink_dir(&self) -> bool;
525    /// Returns `true` if this file type is a symbolic link that is also a file.
526    #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
527    fn is_symlink_file(&self) -> bool;
528}
529
530#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
531impl Sealed for fs::FileType {}
532
533#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
534impl FileTypeExt for fs::FileType {
535    fn is_symlink_dir(&self) -> bool {
536        self.as_inner().is_symlink_dir()
537    }
538    fn is_symlink_file(&self) -> bool {
539        self.as_inner().is_symlink_file()
540    }
541}
542
543/// Windows-specific extensions to [`fs::FileTimes`].
544#[stable(feature = "file_set_times", since = "1.75.0")]
545pub trait FileTimesExt: Sealed {
546    /// Set the creation time of a file.
547    #[stable(feature = "file_set_times", since = "1.75.0")]
548    fn set_created(self, t: SystemTime) -> Self;
549}
550
551#[stable(feature = "file_set_times", since = "1.75.0")]
552impl FileTimesExt for fs::FileTimes {
553    fn set_created(mut self, t: SystemTime) -> Self {
554        self.as_inner_mut().set_created(t.into_inner());
555        self
556    }
557}
558
559/// Creates a new symlink to a non-directory file on the filesystem.
560///
561/// The `link` path will be a file symbolic link pointing to the `original`
562/// path.
563///
564/// The `original` path should not be a directory or a symlink to a directory,
565/// otherwise the symlink will be broken. Use [`symlink_dir`] for directories.
566///
567/// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW].
568/// Note that this [may change in the future][changes].
569///
570/// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
571/// [changes]: io#platform-specific-behavior
572///
573/// # Examples
574///
575/// ```no_run
576/// use std::os::windows::fs;
577///
578/// fn main() -> std::io::Result<()> {
579///     fs::symlink_file("a.txt", "b.txt")?;
580///     Ok(())
581/// }
582/// ```
583///
584/// # Limitations
585///
586/// Windows treats symlink creation as a [privileged action][symlink-security],
587/// therefore this function is likely to fail unless the user makes changes to
588/// their system to permit symlink creation. Users can try enabling Developer
589/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
590/// the process as an administrator.
591///
592/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
593#[stable(feature = "symlink", since = "1.1.0")]
594pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
595    sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
596}
597
598/// Creates a new symlink to a directory on the filesystem.
599///
600/// The `link` path will be a directory symbolic link pointing to the `original`
601/// path.
602///
603/// The `original` path must be a directory or a symlink to a directory,
604/// otherwise the symlink will be broken. Use [`symlink_file`] for other files.
605///
606/// This function currently corresponds to [`CreateSymbolicLinkW`][CreateSymbolicLinkW].
607/// Note that this [may change in the future][changes].
608///
609/// [CreateSymbolicLinkW]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
610/// [changes]: io#platform-specific-behavior
611///
612/// # Examples
613///
614/// ```no_run
615/// use std::os::windows::fs;
616///
617/// fn main() -> std::io::Result<()> {
618///     fs::symlink_dir("a", "b")?;
619///     Ok(())
620/// }
621/// ```
622///
623/// # Limitations
624///
625/// Windows treats symlink creation as a [privileged action][symlink-security],
626/// therefore this function is likely to fail unless the user makes changes to
627/// their system to permit symlink creation. Users can try enabling Developer
628/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
629/// the process as an administrator.
630///
631/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
632#[stable(feature = "symlink", since = "1.1.0")]
633pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
634    sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
635}
636
637/// Creates a junction point.
638///
639/// The `link` path will be a directory junction pointing to the original path.
640/// If `link` is a relative path then it will be made absolute prior to creating the junction point.
641/// The `original` path must be a directory or a link to a directory, otherwise the junction point will be broken.
642///
643/// If either path is not a local file path then this will fail.
644#[unstable(feature = "junction_point", issue = "121709")]
645pub fn junction_point<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
646    sys::fs::junction_point(original.as_ref(), link.as_ref())
647}