use crate::fs_beneath::{open_directory_widening, remove_at};
use crate::subvolume_remove_walk::{empty_directory, verify_below};
use std::path::Path;
pub fn remove_tree(path: &Path) -> std::io::Result<()> {
let metadata: std::fs::Metadata = std::fs::symlink_metadata(path)?;
if !metadata.is_dir() {
return std::fs::remove_file(path);
}
let name: &std::ffi::OsStr = path.file_name().ok_or_else(|| { return std::io::Error::new(std::io::ErrorKind::InvalidInput, format!("{} has no last component to remove", path.display())); })?;
let parent_path: &Path = path.parent().filter(|parent: &&Path| { return !parent.as_os_str().is_empty(); }).unwrap_or_else(|| { return Path::new("."); });
let parent: std::fs::File = std::fs::File::open(parent_path)?;
let top: std::fs::File = open_directory_widening(&parent, name).map_err(|error: std::io::Error| {
if error.raw_os_error() == Some(libc::EXDEV) {
return std::io::Error::new(
std::io::ErrorKind::CrossesDevices,
format!("{} is a mount point, so its content is not part of any tree to remove; unmount it first (`umount {}`)", path.display(), path.display()),
);
}
return error;
})?;
verify_below(&top, path)?;
empty_directory(&top, path)?;
drop(top);
return remove_at(&parent, name, true);
}
#[cfg(test)]
#[path = "subvolume_remove_tests.rs"]
mod tests;