Sanitize file/directory symlinks in path_symlinks on Windows (#1359)
* Sanitize file/directory symlinks in path_symlinks on Windows * Remove redundant error mappings
This commit is contained in:
committed by
GitHub
parent
e64668776a
commit
20e71858a1
@@ -5,7 +5,7 @@ use crate::sys::entry::OsHandle;
|
||||
use crate::wasi::{types, Errno, Result};
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::fs::{File, Metadata, OpenOptions};
|
||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
use std::os::windows::fs::OpenOptionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -413,13 +413,27 @@ pub(crate) fn filestat_set_times(
|
||||
}
|
||||
|
||||
pub(crate) fn symlink(old_path: &str, resolved: PathGet) -> Result<()> {
|
||||
use std::fs;
|
||||
use std::os::windows::fs::{symlink_dir, symlink_file};
|
||||
|
||||
let old_path = concatenate(&resolved.dirfd().as_os_handle(), Path::new(old_path))?;
|
||||
let new_path = resolved.concatenate()?;
|
||||
|
||||
// try creating a file symlink
|
||||
let err = match symlink_file(&old_path, &new_path) {
|
||||
// Windows distinguishes between file and directory symlinks.
|
||||
// If the source doesn't exist or is an exotic file type, we fall back
|
||||
// to regular file symlinks.
|
||||
let use_dir_symlink = fs::metadata(&new_path)
|
||||
.as_ref()
|
||||
.map(Metadata::is_dir)
|
||||
.unwrap_or(false);
|
||||
|
||||
let res = if use_dir_symlink {
|
||||
symlink_dir(&old_path, &new_path)
|
||||
} else {
|
||||
symlink_file(&old_path, &new_path)
|
||||
};
|
||||
|
||||
let err = match res {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(e) => e,
|
||||
};
|
||||
@@ -427,18 +441,15 @@ pub(crate) fn symlink(old_path: &str, resolved: PathGet) -> Result<()> {
|
||||
Some(code) => {
|
||||
log::debug!("path_symlink at symlink_file error code={:?}", code);
|
||||
match code as u32 {
|
||||
winerror::ERROR_NOT_A_REPARSE_POINT => {
|
||||
// try creating a dir symlink instead
|
||||
return symlink_dir(old_path, new_path).map_err(Into::into);
|
||||
}
|
||||
winerror::ERROR_ACCESS_DENIED => {
|
||||
// does the target exist?
|
||||
if new_path.exists() {
|
||||
return Err(Errno::Exist);
|
||||
}
|
||||
}
|
||||
// If the target contains a trailing slash, the Windows API returns
|
||||
// ERROR_INVALID_NAME (which corresponds to ENOENT) instead of
|
||||
// ERROR_ALREADY_EXISTS (which corresponds to EEXIST)
|
||||
//
|
||||
// This concerns only trailing slashes (not backslashes) and
|
||||
// only symbolic links (not hard links).
|
||||
//
|
||||
// Since POSIX will return EEXIST in such case, we simulate this behavior
|
||||
winerror::ERROR_INVALID_NAME => {
|
||||
// does the target without trailing slashes exist?
|
||||
if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved)? {
|
||||
if path.exists() {
|
||||
return Err(Errno::Exist);
|
||||
|
||||
Reference in New Issue
Block a user