use super::chroots::ChrootUnverified;
use super::{GlobalsFinal, Vars};
use crate::snapshot::BackendTypes;
use anyhow::Result as AResult;
use serde::Deserialize;
use std::os::unix::fs::MetadataExt;
use std::path::{Path, PathBuf};
#[derive(Deserialize)]
pub(super) struct WSConfig {
location: String,
backend: Option<BackendTypes>,
}
pub(super) struct Workspace {
location: PathBuf,
backend: BackendTypes,
}
impl WSConfig {
pub(super) fn verify(self, vars: &Vars) -> AResult<Workspace> {
let location = vars.resolve_path(&self.location);
let backend = self.backend.unwrap_or_default();
let meta = match std::fs::metadata(&location) {
Ok(m) => m,
Err(e) => {
log::error!("Failed to get metadata of workspace directory:");
log::error!("{e}");
anyhow::bail!("{e}");
}
};
if meta.uid() != users::get_current_uid() {
let msg = "You are not the owner of the workspace directory";
log::error!("{msg}");
anyhow::bail!(msg);
}
if (meta.mode() & 0o700) != 0o700u32 {
let msg = "Insufficient permissions (rwx) for workspace directory";
log::error!("{msg}");
anyhow::bail!(msg);
}
Ok(Workspace { location, backend })
}
}
impl GlobalsFinal {
#[inline]
pub fn chroot(&self, name: &Path) -> ChrootUnverified {
ChrootUnverified::new(name, &self.cfg.workspace)
}
#[inline]
pub fn workspace(&self) -> &Path {
&self.cfg.workspace
}
#[inline]
pub fn backend(&self) -> BackendTypes {
self.cfg.workspace.backend
}
pub fn list_chroots(&self) -> AResult<Vec<String>> {
let mut chroots = Vec::new();
let contents = std::fs::read_dir(self.cfg.workspace.location.as_path())?;
for content in contents {
let Ok(content) = content else {
log::warn!("Intermittent error in reading workspace");
continue;
};
let name = content.file_name().to_str().unwrap_or_default().to_string();
let name = match content.file_type().map(|x| x.is_dir()) {
Ok(true) => name,
Ok(false) => continue,
Err(e) => {
log::warn!("Error identifying entry type of {name}:");
log::warn!("{e}");
continue;
}
};
chroots.push(name.to_string());
}
Ok(chroots)
}
}
impl std::ops::Deref for Workspace {
type Target = Path;
#[inline]
fn deref(&self) -> &Self::Target {
self.location.as_path()
}
}