Skip to content

Commit 77c2d98

Browse files
committed
fix symlink test on windows
1 parent 1849b41 commit 77c2d98

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

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

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,8 +1033,8 @@ impl Dir {
10331033
}
10341034

10351035
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(&self, original: P, link: Q) -> io::Result<()> {
1036-
run_path_with_utf16(original.as_ref(), &|orig| {
1037-
self.symlink_native(orig, link.as_ref(), original.as_ref().is_relative())
1036+
run_path_with_utf16(link.as_ref(), &|l| {
1037+
self.symlink_native(original.as_ref(), l.as_ref(), link.as_ref().is_relative())
10381038
})
10391039
}
10401040

@@ -1193,18 +1193,19 @@ impl Dir {
11931193
.io_result()
11941194
}
11951195

1196-
fn symlink_native(&self, original: &[u16], link: &Path, relative: bool) -> io::Result<()> {
1196+
fn symlink_native(&self, original: &Path, link: &[u16], relative: bool) -> io::Result<()> {
11971197
const TOO_LONG_ERR: io::Error =
11981198
io::const_error!(io::ErrorKind::InvalidFilename, "File name is too long");
11991199
let mut opts = OpenOptions::new();
12001200
opts.write(true);
1201-
let linkfile = File::open(link, &opts)?;
1202-
let utf16: Vec<u16> = original.iter().chain(original).copied().collect();
1203-
let file_name_len = u16::try_from(original.len()).or(Err(TOO_LONG_ERR))?;
1201+
let linkfile = self.open_with(original, &opts)?;
1202+
let file_name_len = u16::try_from(link.len()).or(Err(TOO_LONG_ERR))?;
1203+
let utf16 =
1204+
b"\\??\\".iter().map(|&n| n as u16).chain(link.iter().copied()).collect::<Vec<u16>>();
12041205
let sym_buffer = c::SYMBOLIC_LINK_REPARSE_BUFFER {
12051206
SubstituteNameOffset: 0,
1206-
SubstituteNameLength: file_name_len,
1207-
PrintNameOffset: file_name_len,
1207+
SubstituteNameLength: file_name_len + 4,
1208+
PrintNameOffset: 4,
12081209
PrintNameLength: file_name_len,
12091210
Flags: if relative { c::SYMLINK_FLAG_RELATIVE } else { 0 },
12101211
PathBuffer: 0,
@@ -1214,15 +1215,21 @@ impl Dir {
12141215
.extend(Layout::new::<c::SYMBOLIC_LINK_REPARSE_BUFFER>())
12151216
.or(Err(TOO_LONG_ERR))?
12161217
.0;
1217-
let layout = Layout::array::<u16>(original.len() * 2)
1218+
let layout = Layout::array::<u16>(link.len() * 2)
12181219
.and_then(|arr| layout.extend(arr))
12191220
.or(Err(TOO_LONG_ERR))?
12201221
.0;
12211222
let buffer = unsafe { alloc(layout) }.cast::<c::REPARSE_DATA_BUFFER>();
12221223
unsafe {
12231224
buffer.write(c::REPARSE_DATA_BUFFER {
12241225
ReparseTag: c::IO_REPARSE_TAG_SYMLINK,
1225-
ReparseDataLength: u16::try_from(size_of_val(&sym_buffer)).or(Err(TOO_LONG_ERR))?,
1226+
ReparseDataLength: u16::try_from(
1227+
size_of::<c::REPARSE_DATA_BUFFER>()
1228+
+ size_of::<c::SYMBOLIC_LINK_REPARSE_BUFFER>()
1229+
+ usize::from(file_name_len) * 2
1230+
- offset_of!(c::REPARSE_DATA_BUFFER, Reserved),
1231+
)
1232+
.or(Err(TOO_LONG_ERR))?,
12261233
Reserved: 0,
12271234
rest: (),
12281235
});
@@ -1236,15 +1243,20 @@ impl Dir {
12361243
.add(offset_of!(c::REPARSE_DATA_BUFFER, rest))
12371244
.add(offset_of!(c::SYMBOLIC_LINK_REPARSE_BUFFER, PathBuffer))
12381245
.cast::<u16>(),
1239-
original.len() * 2,
1246+
link.len() * 2,
12401247
);
12411248
};
12421249
let result = unsafe {
12431250
c::DeviceIoControl(
12441251
linkfile.handle.as_raw_handle(),
12451252
c::FSCTL_SET_REPARSE_POINT,
12461253
&raw const buffer as *const c_void,
1247-
u32::try_from(size_of_val(&buffer)).or(Err(TOO_LONG_ERR))?,
1254+
u32::try_from(
1255+
size_of::<c::REPARSE_DATA_BUFFER>()
1256+
+ size_of::<c::SYMBOLIC_LINK_REPARSE_BUFFER>()
1257+
+ usize::from(file_name_len) * 2,
1258+
)
1259+
.or(Err(TOO_LONG_ERR))?,
12481260
ptr::null_mut(),
12491261
0,
12501262
ptr::null_mut(),

0 commit comments

Comments
 (0)