use crate::docker_service::error::{DockerServiceError, DockerServiceResult};
use std::fs;
use std::path::PathBuf;
use tracing::{debug, info, warn};
#[derive(Debug, Clone)]
pub struct DirectoryPermissionManager {
work_dir: PathBuf,
}
impl DirectoryPermissionManager {
pub fn new(work_dir: PathBuf) -> Self {
Self { work_dir }
}
pub fn ensure_mysql_config_safe(&self) -> DockerServiceResult<()> {
info!("🔒 Checking MySQL config file permissions...");
self.ensure_mysql_config_permissions()?;
info!("✅ MySQL config file permission check completed");
Ok(())
}
fn ensure_mysql_config_permissions(&self) -> DockerServiceResult<()> {
let mysql_cnf = self.work_dir.join("config/mysql.cnf");
if !mysql_cnf.exists() {
debug!("MySQL config file not found, skipping permission setup");
return Ok(());
}
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
if let Ok(metadata) = fs::metadata(&mysql_cnf) {
let current_mode = metadata.permissions().mode() & 0o777;
let is_unsafe = (current_mode & 0o022) != 0;
if is_unsafe {
warn!(
"⚠️ MySQL config file permissions are unsafe: {:o} (MySQL may ignore it)",
current_mode
);
}
}
let metadata = fs::metadata(&mysql_cnf).map_err(|e| {
DockerServiceError::FileSystem(format!(
"Failed to read config file metadata: {}",
e
))
})?;
let mut permissions = metadata.permissions();
permissions.set_mode(0o644);
fs::set_permissions(&mysql_cnf, permissions).map_err(|e| {
DockerServiceError::FileSystem(format!(
"Failed to set config file permissions: {}",
e
))
})?;
info!("🔒 MySQL config file permission: 644 (safe)");
}
#[cfg(windows)]
{
if let Ok(metadata) = fs::metadata(&mysql_cnf) {
let mut permissions = metadata.permissions();
permissions.set_readonly(false);
fs::set_permissions(&mysql_cnf, permissions).ok();
}
info!("🔒 Windows: MySQL config file permission has been set");
}
Ok(())
}
}