use std::path::Path;
use tokio::fs;
use crate::{utils::MERGED_SUBDIR, MonocoreResult};
use super::PermissionGuard;
pub async fn unmount(#[allow(unused_variables)] dest_dir: impl AsRef<Path>) -> MonocoreResult<()> {
#[cfg(all(target_os = "linux", feature = "overlayfs"))]
{
use crate::MonocoreError;
use std::process::Command;
let merged_dir = dest_dir.as_ref().join(MERGED_SUBDIR);
let output = Command::new("mountpoint")
.arg("-q") .arg(&merged_dir)
.status();
if output.map_or(false, |status| status.success()) {
tracing::info!("Unmounting overlayfs at {}", merged_dir.display());
let status = Command::new("umount").arg(&merged_dir).status()?;
if !status.success() {
tracing::warn!("Failed to unmount overlayfs normally, trying force unmount");
let force_status = Command::new("umount")
.arg("-f") .arg(&merged_dir)
.status()?;
if !force_status.success() {
tracing::warn!("Force unmount failed, trying lazy unmount");
let lazy_status = Command::new("umount")
.arg("-l") .arg(&merged_dir)
.status()?;
if !lazy_status.success() {
tracing::error!("All unmount attempts failed for {}", merged_dir.display());
return Err(MonocoreError::LayerHandling {
source: std::io::Error::new(
std::io::ErrorKind::Other,
"Failed to unmount overlayfs",
),
layer: merged_dir.display().to_string(),
});
}
}
}
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
}
}
Ok(())
}
pub async fn remove(dest_dir: impl AsRef<Path>) -> MonocoreResult<()> {
let dest_dir = dest_dir.as_ref();
unmount(dest_dir).await?;
remove_internal(dest_dir).await
}
async fn remove_internal(dest_dir: impl AsRef<Path>) -> MonocoreResult<()> {
let merged_dir = dest_dir.as_ref().join(MERGED_SUBDIR);
if merged_dir.exists() {
let mut perm_guard = PermissionGuard::new();
let mut dir_stack = vec![merged_dir.clone()];
while let Some(dir) = dir_stack.pop() {
perm_guard.make_readable_writable(&dir).await?;
if let Ok(mut entries) = fs::read_dir(&dir).await {
while let Ok(Some(entry)) = entries.next_entry().await {
if let Ok(file_type) = entry.file_type().await {
if file_type.is_dir() {
dir_stack.push(entry.path());
}
}
}
}
}
match fs::remove_dir_all(&merged_dir).await {
Ok(_) => tracing::debug!("Successfully removed {}", merged_dir.display()),
Err(e) => {
tracing::error!("Failed to remove {}: {}", merged_dir.display(), e);
return Err(e.into());
}
}
}
Ok(())
}