Skip to content
metadata.rs 4.41 KiB
Newer Older
use crate::{
    aead::encrypt_file_buffered, errors::CvfsErrors, errors::CvfsResult, secure_file::ActiveFile,
};
use multi_key_manager::{file::File, LiveKeyMaterial, LiveKeys, MutableNonce, OpeningNonce};
use ring::aead::{BoundKey, SealingKey, UnboundKey};
Stefan Schindler's avatar
Stefan Schindler committed
use serde::{Deserialize, Serialize};
Stefan Schindler's avatar
Stefan Schindler committed
use std::{cell::RefCell, collections::HashMap, fmt::Debug, io::Write, rc::Rc};
Stefan Schindler's avatar
Stefan Schindler committed
pub type PathString = String;

Stefan Schindler's avatar
Stefan Schindler committed
#[derive(Serialize, Deserialize)]
pub struct Metadata {
Stefan Schindler's avatar
Stefan Schindler committed
    pub(crate) files: HashMap<PathString, FileInfo>,
impl Metadata {
    /// creates a new empty index
    pub fn empty() -> Self {
        Self {
            files: HashMap::new(),
        }
Stefan Schindler's avatar
Stefan Schindler committed
    pub fn restore_from_slice(input: &[u8]) -> CvfsResult<Self> {
        let files = rmp_serde::from_slice(input)?;
        Ok(Self { files })
    pub(crate) fn store_to_disk(
        &mut self,
        mut output: File,
        key_material: &mut LiveKeys,
    ) -> CvfsResult<()> {
        // flush all the open files
        for active in self
            .files
            .values_mut()
            .filter(|element| element.active.is_some())
        {
            let algorithm = &ring::aead::CHACHA20_POLY1305;
            let unbound = UnboundKey::new(
                algorithm,
                key_material.unsafe_insecure_borrow_i_know_what_i_am_doing(),
            )?;

            let shared_nonce = Rc::new(RefCell::new(active.nonce));
            {
                let nonce = MutableNonce::new(Rc::clone(&shared_nonce));
                let mut key = SealingKey::new(unbound, nonce);

                active
                    .active
                    .as_mut()
                    .expect("already filtered")
                    .try_flush(&mut key)?;
            }
            active.nonce = *shared_nonce.borrow();
        }

        // flush the index
        let buf = rmp_serde::to_vec_named(&self.files)?;
Stefan Schindler's avatar
Stefan Schindler committed
        //println!("Metadata serialised buffer len: {}", buf.len());
        assert!(buf.len() > 0, "unable to serialise files");

        let mut key = key_material.get_sealing_master_key();
Stefan Schindler's avatar
Stefan Schindler committed
        encrypt_file_buffered(&mut output, &buf, &mut key)?;

        output.flush()?;

        println!("Metadata::store_to_disk flush ok");

        Ok(())
    }
Stefan Schindler's avatar
Stefan Schindler committed

    pub fn find_active_file(&mut self, id: &FileTag) -> CvfsResult<&mut ActiveFile> {
Stefan Schindler's avatar
Stefan Schindler committed
        self.files
            .values_mut()
            .filter_map(|element| match &mut element.active {
                Some(active) if active.id == *id => Some(active),
                _ => None,
Stefan Schindler's avatar
Stefan Schindler committed
            })
            .next()
            .ok_or_else(|| CvfsErrors::FileHandlerNotFound(id.clone()))
Stefan Schindler's avatar
Stefan Schindler committed
    }
impl Debug for Metadata {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Metadata")
            .field("files", &format_args!("{:#?}", &self.files))
            //f.debug_list()
            //    .entries(self.files.entries())
            .finish()
    }
}
Stefan Schindler's avatar
Stefan Schindler committed
/// Information stored per file, except the path in the virtual file sytem
#[derive(Serialize, Deserialize)]
Stefan Schindler's avatar
Stefan Schindler committed
pub struct FileInfo {
    /// this exists if the file is already open
Stefan Schindler's avatar
Stefan Schindler committed
    #[serde(skip)]
    pub(crate) active: Option<ActiveFile>,
    /// Don't store the full path so the archive stays protable
    pub(crate) real_block_name: String,
Stefan Schindler's avatar
Stefan Schindler committed
    /// keep this as private as possible
    nonce: u128,
impl FileInfo {
    pub fn new(real_block_name: String) -> Self {
        Self {
            active: None,
Stefan Schindler's avatar
Stefan Schindler committed
            nonce: 1,
Stefan Schindler's avatar
Stefan Schindler committed

    pub fn get_opening_nonce(&self) -> OpeningNonce {
        OpeningNonce::new(self.nonce.clone())
    }
}
impl core::fmt::Debug for FileInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("FileInfo")
Stefan Schindler's avatar
Stefan Schindler committed
            .field(
                "real_path",
                &format_args!(
                    crate::BLOCK_PATH,
                    self.real_block_name //self.real_path.file_name().unwrap_or_default()
Stefan Schindler's avatar
Stefan Schindler committed
                ),
            )
            .finish()
    }
pub struct FileTag(pub(crate) u64);
    pub fn next(file_tag_counter: &mut u64) -> Self {
        //FileTag(file_tag_counter.fetch_add(1, Ordering::SeqCst))
        let id = file_tag_counter.clone();
        *file_tag_counter += 1;
        FileTag(id)
    }
}
#[cfg(test)]
mod tests {
    use super::*;