Skip to content

Commit d497f32

Browse files
authored
Rollup merge of rust-lang#38921 - chris-morgan:windows-unprivileged-symlink-creation, r=alexcrichton
Support unprivileged symlink creation in Windows Symlink creation on Windows has in the past basically required admin; it’s being opened up a bit in the Creators Update, so that at least people who have put their computers into Developer Mode will be able to create symlinks without special privileges. (It’s unclear from what Microsoft has said whether Developer Mode will be required in the final Creators Update release, but sadly I expect it still will be, so this *still* won’t be as helpful as I’d like.) Because of compatibility concerns, they’ve hidden this new functionality behind a new flag in the CreateSymbolicLink dwFlags: `SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE`. So we add this flag in order to join the party. Sources: - https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/ is the official announcement (search for CreateSymbolicLink) - https://news.ycombinator.com/item?id=13096354 on why the new flag.
2 parents 9874fff + 02ae1e1 commit d497f32

File tree

2 files changed

+20
-3
lines changed

2 files changed

+20
-3
lines changed

src/libstd/sys/windows/c.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ pub const SYMLINK_FLAG_RELATIVE: DWORD = 0x00000001;
167167
pub const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4;
168168

169169
pub const SYMBOLIC_LINK_FLAG_DIRECTORY: DWORD = 0x1;
170+
pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD = 0x2;
170171

171172
// Note that these are not actually HANDLEs, just values to pass to GetStdHandle
172173
pub const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD;

src/libstd/sys/windows/fs.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -646,9 +646,25 @@ pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> {
646646
let src = to_u16s(src)?;
647647
let dst = to_u16s(dst)?;
648648
let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 };
649-
cvt(unsafe {
650-
c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL
651-
})?;
649+
// Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10
650+
// Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the
651+
// computer is in Developer Mode, but SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE must be
652+
// added to dwFlags to opt into this behaviour.
653+
let result = cvt(unsafe {
654+
c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(),
655+
flags | c::SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) as c::BOOL
656+
});
657+
if let Err(err) = result {
658+
if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) {
659+
// Older Windows objects to SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE,
660+
// so if we encounter ERROR_INVALID_PARAMETER, retry without that flag.
661+
cvt(unsafe {
662+
c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as c::BOOL
663+
})?;
664+
} else {
665+
return Err(err);
666+
}
667+
}
652668
Ok(())
653669
}
654670

0 commit comments

Comments
 (0)