diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 910d802f05902..7b8575f9ec4c7 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -166,6 +166,7 @@ pub const SYMLINK_FLAG_RELATIVE: DWORD = 0x00000001; pub const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4; pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1; +pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2; // Note that these are not actually HANDLEs, just values to pass to GetStdHandle pub const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD; diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index c410fcd1ee0ed..4efc68afdc4c7 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -646,9 +646,25 @@ pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> { let src = to_u16s(src)?; let dst = to_u16s(dst)?; let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 }; - cvt(unsafe { - c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL - })?; + // Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10 + // Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the + // computer is in Developer Mode, but SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE must be + // added to dwFlags to opt into this behaviour. + let result = cvt(unsafe { + c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), + flags | c::SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) as c::BOOL + }); + if let Err(err) = result { + if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) { + // Older Windows objects to SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE, + // so if we encounter ERROR_INVALID_PARAMETER, retry without that flag. + cvt(unsafe { + c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL + })?; + } else { + return Err(err); + } + } Ok(()) }