Skip to content

Commit

Permalink
Fix Windows "access is denied" removing a dangling symlink
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Aug 30, 2022
1 parent c4ee13e commit 6d78b8e
Showing 1 changed file with 22 additions and 12 deletions.
34 changes: 22 additions & 12 deletions gen/build/src/out.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,24 +86,34 @@ pub(crate) fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) ->
fn best_effort_remove(path: &Path) {
use std::fs;

let file_type = match if cfg!(windows) {
if cfg!(windows) {
// On Windows, the correct choice of remove_file vs remove_dir needs to
// be used according to what the symlink *points to*. Trying to use
// remove_file to remove a symlink which points to a directory fails
// with "Access is denied".
fs::metadata(path).or_else(|_| fs::symlink_metadata(path))
if let Ok(metadata) = fs::metadata(path) {
if metadata.is_dir() {
let _ = fs::remove_dir_all(path);
} else {
let _ = fs::remove_file(path);
}
} else if fs::symlink_metadata(path).is_ok() {
// The symlink might exist but be dangling, in which case there is
// no standard way to determine what "kind" of symlink it is. Try
// deleting both ways.
if fs::remove_dir_all(path).is_err() {
let _ = fs::remove_file(path);
}
}
} else {
// On non-Windows, we check metadata not following symlinks. All
// symlinks are removed using remove_file.
fs::symlink_metadata(path)
} {
Ok(metadata) => metadata.file_type(),
Err(_) => return,
};

if file_type.is_dir() {
let _ = fs::remove_dir_all(path);
} else {
let _ = fs::remove_file(path);
if let Ok(metadata) = fs::symlink_metadata(path) {
if metadata.is_dir() {
let _ = fs::remove_dir_all(path);
} else {
let _ = fs::remove_file(path);
}
}
}
}

0 comments on commit 6d78b8e

Please sign in to comment.