Skip to content

Commit d945ac0

Browse files
committed
Fallbacks for CreateSymbolicLinkW, CreateHardLinkW, GetFinalPathNameByHandleW
- `CreateSymbolicLinkW` is used in `std::fs::soft_link`. Fails on unsupported systems. - `CreateHardLinkW` is used in `std::fs::hard_link`. - `GetFinalPathNameByHandleW` is used in `std::fs::canonicalize`. Systems that don't support `GetFinalPathNameByHandleW` also don't support symlinks, so the fallback uses `GetFullPathNameW` instead.
1 parent cd96968 commit d945ac0

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

library/std/src/sys/windows/c.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,28 @@ compat_fn_with_fallback! {
376376

377377
TRUE
378378
}
379+
380+
// >= Vista / Server 2008
381+
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
382+
pub fn CreateSymbolicLinkW(
383+
lpsymlinkfilename: PCWSTR,
384+
lptargetfilename: PCWSTR,
385+
dwflags: SYMBOLIC_LINK_FLAGS,
386+
) -> BOOLEAN {
387+
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
388+
0
389+
}
390+
391+
// >= 2000
392+
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createhardlinkw
393+
pub fn CreateHardLinkW(
394+
lpfilename: PCWSTR,
395+
lpexistingfilename: PCWSTR,
396+
lpsecurityattributes: *const SECURITY_ATTRIBUTES,
397+
) -> BOOL {
398+
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
399+
FALSE
400+
}
379401
}
380402

381403
compat_fn_lazy! {
@@ -396,6 +418,15 @@ compat_fn_lazy! {
396418
lpfileinformation: *mut ::core::ffi::c_void,
397419
dwbuffersize: u32,
398420
) -> BOOL;
421+
422+
// >= Vista / Server 2008
423+
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
424+
pub fn GetFinalPathNameByHandleW(
425+
hfile: HANDLE,
426+
lpszfilepath: PWSTR,
427+
cchfilepath: u32,
428+
dwflags: GETFINALPATHNAMEBYHANDLE_FLAGS,
429+
) -> u32;
399430
}
400431

401432
compat_fn_optional! {

library/std/src/sys/windows/fs.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,13 +1381,24 @@ fn get_path(f: &File) -> io::Result<PathBuf> {
13811381
}
13821382

13831383
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
1384-
let mut opts = OpenOptions::new();
1385-
// No read or write permissions are necessary
1386-
opts.access_mode(0);
1387-
// This flag is so we can open directories too
1388-
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
1389-
let f = File::open(p, &opts)?;
1390-
get_path(&f)
1384+
if c::GetFinalPathNameByHandleW::option().is_some() {
1385+
let mut opts = OpenOptions::new();
1386+
// No read or write permissions are necessary
1387+
opts.access_mode(0);
1388+
// This flag is so we can open directories too
1389+
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
1390+
let f = File::open(p, &opts)?;
1391+
get_path(&f)
1392+
} else {
1393+
// systems that don't support GetFinalPathNameByHandleW also don't support symlinks, so we
1394+
// fall back to using GetFullPathName.
1395+
let path = maybe_verbatim(p)?;
1396+
let mut file_part = ptr::null_mut();
1397+
super::fill_utf16_buf(
1398+
|buf, sz| unsafe { c::GetFullPathNameW(path.as_ptr(), sz, buf, &mut file_part) },
1399+
|buf| PathBuf::from(OsString::from_wide(buf)),
1400+
)
1401+
}
13911402
}
13921403

13931404
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {

0 commit comments

Comments
 (0)