bandsocks-runtime 0.1.0

Experimental embeddable container sandbox (not working yet)
use crate::filesystem::vfs::{Filesystem, Stat};
use crate::filesystem::mmap::MapRef;
use crate::errors::ImageError;
use tar::{Archive, Entry, EntryType};
use std::io::{Read, Cursor};
use std::sync::Arc;
use memmap::Mmap;

pub fn extract_metadata(mut fs: &mut Filesystem, archive: &Arc<Mmap>) -> Result<(), ImageError> {
    let mut offset: usize = 0;
    while let Some(entry) = Archive::new(Cursor::new(&archive[offset..])).entries()?.next() {
        let entry = entry?;
        let file_begin = offset + (entry.raw_file_position() as usize);
        let file = MapRef::new(archive, file_begin, entry.size() as usize);
        offset = pad_to_block_multiple(file_begin + entry.size() as usize);
        extract_file_metadata(&mut fs, entry, file)?;
    }
    Ok(())
}

fn pad_to_block_multiple(size: usize) -> usize{
    const BLOCK_LEN: usize = 512;
    let rem = size % BLOCK_LEN;
    if rem == 0 {
        size
    } else {
        size + (BLOCK_LEN - rem)
    }
}

fn extract_file_metadata<'a, R: Read> (fs: &mut Filesystem, entry: Entry<'a, R>, file: MapRef) -> Result<(), ImageError> {
    let mut fsw = fs.writer();
    let kind = entry.header().entry_type();
    let path = entry.path()?;
    let link_name = entry.link_name()?;
    let stat = Stat {
        mode: entry.header().mode()?,
        uid: entry.header().uid()?,
        gid: entry.header().gid()?,
        mtime: entry.header().mtime()?,
        ..Default::default()
    };

    match kind {
        EntryType::Regular => fsw.write_file_mapping(&path, file, stat)?,
        EntryType::Directory => fsw.write_directory_metadata(&path, stat)?,
        EntryType::Symlink => match link_name {
            Some(link_name) => fsw.write_symlink(&path, &link_name, stat)?,
            None => Err(ImageError::TARFileError)?,
        },
        EntryType::Link => match link_name {
            Some(link_name) => fsw.write_hardlink(&path, &link_name)?,
            None => Err(ImageError::TARFileError)?,
        },
        _ => log::error!("skipping unsupported tar file entry type {:?}, {:?}", kind, entry.header()),
    }

    Ok(())
}