buntrail-services 0.1.0

Filesystem, Git, terminal, search and connection services.
Documentation
use crate::files::{io_error, private_directory};
use buntrail_core::contracts::{CoreError, RuntimeGeneration};
use std::{
    collections::HashSet,
    fs::{File, OpenOptions},
    os::unix::fs::OpenOptionsExt,
    path::{Path, PathBuf},
};

pub(crate) struct RuntimeGuard {
    file: File,
}
fn name(runtime: &RuntimeGeneration) -> String {
    runtime
        .supervisor_boot
        .iter()
        .map(|byte| format!("{byte:02x}"))
        .collect()
}
fn open(path: PathBuf) -> std::io::Result<File> {
    OpenOptions::new()
        .read(true)
        .write(true)
        .custom_flags(libc::O_NOFOLLOW)
        .open(path)
}
impl RuntimeGuard {
    pub fn create(directory: &Path, runtime: &RuntimeGeneration) -> Result<Self, CoreError> {
        private_directory(directory)?;
        let file = OpenOptions::new()
            .read(true)
            .write(true)
            .create_new(true)
            .mode(0o600)
            .custom_flags(libc::O_NOFOLLOW)
            .open(directory.join(name(runtime)))
            .map_err(io_error)?;
        file.lock().map_err(io_error)?;
        Ok(Self { file })
    }
    pub fn dead(directory: &Path, runtime: &RuntimeGeneration) -> bool {
        if runtime.container_start.is_some() {
            return false;
        }
        let Ok(file) = open(directory.join(name(runtime))) else {
            return false;
        };
        if file.try_lock().is_err() {
            return false;
        }
        let _ = file.unlock();
        true
    }
    pub fn clean_unreferenced(directory: &Path, referenced: &HashSet<String>) {
        let Ok(entries) = std::fs::read_dir(directory) else {
            return;
        };
        for entry in entries.flatten() {
            let Some(name) = entry.file_name().to_str().map(str::to_owned) else {
                continue;
            };
            if name.len() != 32
                || !name.bytes().all(|byte| byte.is_ascii_hexdigit())
                || referenced.contains(&name)
            {
                continue;
            }
            let Ok(file) = open(entry.path()) else {
                continue;
            };
            if file.try_lock().is_ok() {
                let _ = std::fs::remove_file(entry.path());
                let _ = file.unlock();
            }
        }
    }
}
impl Drop for RuntimeGuard {
    fn drop(&mut self) {
        let _ = self.file.unlock();
    }
}
pub(crate) fn runtime_name(runtime: &RuntimeGeneration) -> String {
    name(runtime)
}