Fix path_rename_trailing_slashes test case on Win
This commit adds a utility routine `strip_trailing_slashes_and_concatenate` which is common for `path_rename` and `path_symlink` on Windows, and checks if the resolved `PathGet` indeed contains a trailing slash(es) before striping them off. Secondly, this commit fixes `path_rename_trailing_slashes` test case by adding two additional checks for potentially erroneous conditions, and raising `ENOTDIR` if any happens to be true.
This commit is contained in:
1
build.rs
1
build.rs
@@ -198,7 +198,6 @@ mod wasm_tests {
|
|||||||
"symlink_loop" => true,
|
"symlink_loop" => true,
|
||||||
"truncation_rights" => true,
|
"truncation_rights" => true,
|
||||||
"fd_readdir" => true,
|
"fd_readdir" => true,
|
||||||
"path_rename_trailing_slashes" => true,
|
|
||||||
"poll_oneoff" => true,
|
"poll_oneoff" => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,19 +211,33 @@ pub(crate) fn path_readlink(resolved: PathGet, buf: &mut [u8]) -> Result<usize>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn strip_trailing_slashes_and_concatenate(resolved: &PathGet) -> Result<Option<PathBuf>> {
|
||||||
|
if resolved.path().ends_with('/') {
|
||||||
|
let suffix = resolved.path().trim_end_matches('/');
|
||||||
|
concatenate(resolved.dirfd(), Path::new(suffix)).map(Some)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> {
|
pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> {
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
let old_path = resolved_old.concatenate()?;
|
let old_path = resolved_old.concatenate()?;
|
||||||
let new_path = resolved_new.concatenate()?;
|
let new_path = resolved_new.concatenate()?;
|
||||||
|
|
||||||
// First, sanity check that we're not trying to rename dir to file or vice versa.
|
// First sanity check: check we're not trying to rename dir to file or vice versa.
|
||||||
// NB on Windows, the former is actually permitted [std::fs::rename].
|
// NB on Windows, the former is actually permitted [std::fs::rename].
|
||||||
//
|
//
|
||||||
// [std::fs::rename]: https://doc.rust-lang.org/std/fs/fn.rename.html
|
// [std::fs::rename]: https://doc.rust-lang.org/std/fs/fn.rename.html
|
||||||
if old_path.is_dir() && new_path.is_file() {
|
if old_path.is_dir() && new_path.is_file() {
|
||||||
return Err(Error::ENOTDIR);
|
return Err(Error::ENOTDIR);
|
||||||
}
|
}
|
||||||
|
// Second sanity check: check we're not trying to rename a file into a path
|
||||||
|
// ending in a trailing slash.
|
||||||
|
if old_path.is_file() && resolved_new.path().ends_with('/') {
|
||||||
|
return Err(Error::ENOTDIR);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO handle symlinks
|
// TODO handle symlinks
|
||||||
|
|
||||||
@@ -246,6 +260,16 @@ pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Resul
|
|||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
WinError::ERROR_INVALID_NAME => {
|
||||||
|
// If source contains trailing slashes, check if we are dealing with
|
||||||
|
// a file instead of a dir, and if so, throw ENOTDIR.
|
||||||
|
if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved_old)? {
|
||||||
|
if path.is_file() {
|
||||||
|
return Err(Error::ENOTDIR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(WinError::ERROR_INVALID_NAME.into())
|
||||||
|
}
|
||||||
e => Err(e.into()),
|
e => Err(e.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,14 +380,13 @@ pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> {
|
|||||||
}
|
}
|
||||||
WinError::ERROR_INVALID_NAME => {
|
WinError::ERROR_INVALID_NAME => {
|
||||||
// does the target without trailing slashes exist?
|
// does the target without trailing slashes exist?
|
||||||
let suffix = resolved.path().trim_end_matches('/');
|
if let Some(path) = strip_trailing_slashes_and_concatenate(&resolved)? {
|
||||||
let out_path = concatenate(resolved.dirfd(), Path::new(suffix))?;
|
if path.exists() {
|
||||||
if out_path.exists() {
|
return Err(Error::EEXIST);
|
||||||
Err(Error::EEXIST)
|
|
||||||
} else {
|
|
||||||
Err(WinError::ERROR_INVALID_NAME.into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(WinError::ERROR_INVALID_NAME.into())
|
||||||
|
}
|
||||||
e => Err(e.into()),
|
e => Err(e.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user