mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
fix: remove symlink on Windows
Signed-off-by: hi-rustin <rustin.liu@gmail.com>
This commit is contained in:
parent
0e1b115ccd
commit
40ff7be1ad
@ -517,24 +517,57 @@ fn _remove_dir(p: &Path) -> Result<()> {
|
|||||||
///
|
///
|
||||||
/// If the file is readonly, this will attempt to change the permissions to
|
/// If the file is readonly, this will attempt to change the permissions to
|
||||||
/// force the file to be deleted.
|
/// force the file to be deleted.
|
||||||
|
/// On Windows, if the file is a symlink to a directory, this will attempt to remove
|
||||||
|
/// the symlink itself.
|
||||||
pub fn remove_file<P: AsRef<Path>>(p: P) -> Result<()> {
|
pub fn remove_file<P: AsRef<Path>>(p: P) -> Result<()> {
|
||||||
_remove_file(p.as_ref())
|
_remove_file(p.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _remove_file(p: &Path) -> Result<()> {
|
fn _remove_file(p: &Path) -> Result<()> {
|
||||||
let mut err = match fs::remove_file(p) {
|
// For Windows, we need to check if the file is a symlink to a directory
|
||||||
Ok(()) => return Ok(()),
|
// and remove the symlink itself by calling `remove_dir` instead of
|
||||||
Err(e) => e,
|
// `remove_file`.
|
||||||
};
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
if err.kind() == io::ErrorKind::PermissionDenied && set_not_readonly(p).unwrap_or(false) {
|
use std::os::windows::fs::FileTypeExt;
|
||||||
match fs::remove_file(p) {
|
let metadata = symlink_metadata(p)?;
|
||||||
Ok(()) => return Ok(()),
|
let file_type = metadata.file_type();
|
||||||
Err(e) => err = e,
|
if file_type.is_symlink_dir() {
|
||||||
|
return remove_symlink_dir_with_permission_check(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(err).with_context(|| format!("failed to remove file `{}`", p.display()))
|
remove_file_with_permission_check(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn remove_symlink_dir_with_permission_check(p: &Path) -> Result<()> {
|
||||||
|
remove_with_permission_check(fs::remove_dir, p)
|
||||||
|
.with_context(|| format!("failed to remove symlink dir `{}`", p.display()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_file_with_permission_check(p: &Path) -> Result<()> {
|
||||||
|
remove_with_permission_check(fs::remove_file, p)
|
||||||
|
.with_context(|| format!("failed to remove file `{}`", p.display()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_with_permission_check<F, P>(remove_func: F, p: P) -> io::Result<()>
|
||||||
|
where
|
||||||
|
F: Fn(P) -> io::Result<()>,
|
||||||
|
P: AsRef<Path> + Clone,
|
||||||
|
{
|
||||||
|
match remove_func(p.clone()) {
|
||||||
|
Ok(()) => Ok(()),
|
||||||
|
Err(e) => {
|
||||||
|
if e.kind() == io::ErrorKind::PermissionDenied
|
||||||
|
&& set_not_readonly(p.as_ref()).unwrap_or(false)
|
||||||
|
{
|
||||||
|
remove_func(p)
|
||||||
|
} else {
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_not_readonly(p: &Path) -> io::Result<bool> {
|
fn set_not_readonly(p: &Path) -> io::Result<bool> {
|
||||||
@ -926,9 +959,9 @@ mod tests {
|
|||||||
|
|
||||||
assert!(symlink_path.exists());
|
assert!(symlink_path.exists());
|
||||||
|
|
||||||
assert!(remove_file(symlink_path.clone()).is_err());
|
assert!(remove_file(symlink_path.clone()).is_ok());
|
||||||
|
|
||||||
assert!(symlink_path.exists());
|
assert!(!symlink_path.exists());
|
||||||
assert!(dir_path.exists());
|
assert!(dir_path.exists());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user