memflow 0.2.0-beta9

core components of the memflow physical memory introspection framework
Documentation
use crate::error::{Error, ErrorKind, ErrorOrigin, Result};
use crate::mem::MemoryMap;
use crate::types::{umem, Address};
use memmap::{Mmap, MmapMut, MmapOptions};

use core::convert::TryInto;
use std::fs::File;
use std::sync::Arc;

use super::mmap::MappedPhysicalMemory;

#[derive(Clone)]
pub struct MmapInfo<'a> {
    mem_map: MemoryMap<&'a [u8]>,
    _buf: Arc<Mmap>,
}

impl<'a> AsRef<MemoryMap<&'a [u8]>> for MmapInfo<'a> {
    fn as_ref(&self) -> &MemoryMap<&'a [u8]> {
        &self.mem_map
    }
}

impl<'a> MmapInfo<'a> {
    pub fn try_with_filemap(file: File, map: MemoryMap<(Address, umem)>) -> Result<Self> {
        let file_map = unsafe {
            MmapOptions::new().map(&file).map_err(|err| {
                Error(ErrorOrigin::Connector, ErrorKind::UnableToMapFile).log_error(err)
            })?
        };

        Self::try_with_bufmap(file_map, map)
    }

    pub fn try_with_bufmap(buf: Mmap, map: MemoryMap<(Address, umem)>) -> Result<Self> {
        let mut new_map = MemoryMap::new();

        let buf_len = buf.as_ref().len() as umem;
        let buf_ptr = buf.as_ref().as_ptr();

        for (base, (output_base, size)) in map.into_iter() {
            let output_base_umem = output_base.to_umem();
            if output_base_umem >= buf_len {
                return Err(Error(
                    ErrorOrigin::Connector,
                    ErrorKind::MemoryMapOutOfRange,
                ));
            }

            let output_end = std::cmp::min(output_base_umem + size, buf_len);

            new_map.push(base, unsafe {
                std::slice::from_raw_parts(
                    buf_ptr.add(output_base_umem.try_into().unwrap()),
                    (output_end - output_base_umem).try_into().unwrap(),
                )
            });
        }

        Ok(Self {
            mem_map: new_map,
            _buf: Arc::new(buf),
        })
    }

    pub fn into_connector(self) -> ReadMappedFilePhysicalMemory<'a> {
        MappedPhysicalMemory::with_info(self)
    }
}

pub type ReadMappedFilePhysicalMemory<'a> = MappedPhysicalMemory<&'a [u8], MmapInfo<'a>>;

pub struct MmapInfoMut<'a> {
    mem_map: MemoryMap<&'a mut [u8]>,
    _buf: MmapMut,
}

impl<'a> AsRef<MemoryMap<&'a mut [u8]>> for MmapInfoMut<'a> {
    fn as_ref(&self) -> &MemoryMap<&'a mut [u8]> {
        &self.mem_map
    }
}

impl<'a> MmapInfoMut<'a> {
    pub fn try_with_filemap_mut(file: File, map: MemoryMap<(Address, umem)>) -> Result<Self> {
        let file_map = unsafe {
            MmapOptions::new().map_mut(&file).map_err(|err| {
                Error(ErrorOrigin::Connector, ErrorKind::UnableToMapFile).log_error(err)
            })?
        };

        Self::try_with_bufmap_mut(file_map, map)
    }

    pub fn try_with_bufmap_mut(mut buf: MmapMut, map: MemoryMap<(Address, umem)>) -> Result<Self> {
        let mut new_map = MemoryMap::new();

        let buf_len = buf.as_ref().len() as umem;
        let buf_ptr = buf.as_mut().as_mut_ptr();

        for (base, (output_base, size)) in map.into_iter() {
            let output_base_umem = output_base.to_umem();
            if output_base_umem >= buf_len as umem {
                return Err(Error(
                    ErrorOrigin::Connector,
                    ErrorKind::MemoryMapOutOfRange,
                ));
            }

            let output_end = std::cmp::min(output_base_umem + size, buf_len);

            new_map.push(base, unsafe {
                std::slice::from_raw_parts_mut(
                    buf_ptr.add(output_base_umem.try_into().unwrap()),
                    (output_end - output_base_umem).try_into().unwrap(),
                )
            });
        }

        Ok(Self {
            mem_map: new_map,
            _buf: buf,
        })
    }

    pub fn into_connector(self) -> WriteMappedFilePhysicalMemory<'a> {
        MappedPhysicalMemory::with_info(self)
    }
}

pub type WriteMappedFilePhysicalMemory<'a> = MappedPhysicalMemory<&'a mut [u8], MmapInfoMut<'a>>;