Skip to content

Commit 02d8fa7

Browse files
authored
Rollup merge of rust-lang#107978 - ChrisDenton:nt-to-win32, r=m-ou-se
Correctly convert an NT path to a Win32 path in `read_link` This can be done by simply changing the `\??\` prefix to `\\?\`. Currently it strips off the prefix which could lead to the wrong path being returned (e.g. if it's not a drive path or if the path contains trailing spaces, etc). r? libs
2 parents cad92b4 + 178f7bb commit 02d8fa7

File tree

2 files changed

+21
-12
lines changed

2 files changed

+21
-12
lines changed

library/std/src/fs/tests.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,7 @@ fn symlink_noexist() {
919919

920920
#[test]
921921
fn read_link() {
922+
let tmpdir = tmpdir();
922923
if cfg!(windows) {
923924
// directory symlink
924925
assert_eq!(check!(fs::read_link(r"C:\Users\All Users")), Path::new(r"C:\ProgramData"));
@@ -933,8 +934,11 @@ fn read_link() {
933934
Path::new(r"C:\Users")
934935
);
935936
}
937+
// Check that readlink works with non-drive paths on Windows.
938+
let link = tmpdir.join("link_unc");
939+
check!(symlink_dir(r"\\localhost\c$\", &link));
940+
assert_eq!(check!(fs::read_link(&link)), Path::new(r"\\localhost\c$\"));
936941
}
937-
let tmpdir = tmpdir();
938942
let link = tmpdir.join("link");
939943
if !got_symlink_permission(&tmpdir) {
940944
return;

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

+16-11
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ impl File {
477477
fn reparse_point(
478478
&self,
479479
space: &mut Align8<[MaybeUninit<u8>]>,
480-
) -> io::Result<(c::DWORD, *const c::REPARSE_DATA_BUFFER)> {
480+
) -> io::Result<(c::DWORD, *mut c::REPARSE_DATA_BUFFER)> {
481481
unsafe {
482482
let mut bytes = 0;
483483
cvt({
@@ -496,7 +496,7 @@ impl File {
496496
)
497497
})?;
498498
const _: () = assert!(core::mem::align_of::<c::REPARSE_DATA_BUFFER>() <= 8);
499-
Ok((bytes, space.0.as_ptr().cast::<c::REPARSE_DATA_BUFFER>()))
499+
Ok((bytes, space.0.as_mut_ptr().cast::<c::REPARSE_DATA_BUFFER>()))
500500
}
501501
}
502502

@@ -506,22 +506,22 @@ impl File {
506506
unsafe {
507507
let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag {
508508
c::IO_REPARSE_TAG_SYMLINK => {
509-
let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
510-
ptr::addr_of!((*buf).rest).cast();
509+
let info: *mut c::SYMBOLIC_LINK_REPARSE_BUFFER =
510+
ptr::addr_of_mut!((*buf).rest).cast();
511511
assert!(info.is_aligned());
512512
(
513-
ptr::addr_of!((*info).PathBuffer).cast::<u16>(),
513+
ptr::addr_of_mut!((*info).PathBuffer).cast::<u16>(),
514514
(*info).SubstituteNameOffset / 2,
515515
(*info).SubstituteNameLength / 2,
516516
(*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0,
517517
)
518518
}
519519
c::IO_REPARSE_TAG_MOUNT_POINT => {
520-
let info: *const c::MOUNT_POINT_REPARSE_BUFFER =
521-
ptr::addr_of!((*buf).rest).cast();
520+
let info: *mut c::MOUNT_POINT_REPARSE_BUFFER =
521+
ptr::addr_of_mut!((*buf).rest).cast();
522522
assert!(info.is_aligned());
523523
(
524-
ptr::addr_of!((*info).PathBuffer).cast::<u16>(),
524+
ptr::addr_of_mut!((*info).PathBuffer).cast::<u16>(),
525525
(*info).SubstituteNameOffset / 2,
526526
(*info).SubstituteNameLength / 2,
527527
false,
@@ -535,13 +535,18 @@ impl File {
535535
}
536536
};
537537
let subst_ptr = path_buffer.add(subst_off.into());
538-
let mut subst = slice::from_raw_parts(subst_ptr, subst_len as usize);
538+
let subst = slice::from_raw_parts_mut(subst_ptr, subst_len as usize);
539539
// Absolute paths start with an NT internal namespace prefix `\??\`
540540
// We should not let it leak through.
541541
if !relative && subst.starts_with(&[92u16, 63u16, 63u16, 92u16]) {
542-
subst = &subst[4..];
542+
// Turn `\??\` into `\\?\` (a verbatim path).
543+
subst[1] = b'\\' as u16;
544+
// Attempt to convert to a more user-friendly path.
545+
let user = super::args::to_user_path(subst.iter().copied().chain([0]).collect())?;
546+
Ok(PathBuf::from(OsString::from_wide(&user)))
547+
} else {
548+
Ok(PathBuf::from(OsString::from_wide(subst)))
543549
}
544-
Ok(PathBuf::from(OsString::from_wide(subst)))
545550
}
546551
}
547552

0 commit comments

Comments
 (0)