mkups 0.1.0

Toolkit for creating, applying, and inspecting .ups patches
Documentation
use std::{slice, fs::File, ffi::c_void, num::NonZeroUsize};
use std::os::unix::prelude::*;
use nix::{errno::Errno, sys::mman::{mmap, munmap, ProtFlags, MapFlags}};

pub struct MappedFile {
    addr: *mut c_void,
    len: usize,
}

#[derive(Debug)]
pub enum MapError {
    ZeroLength,
    Io(std::io::Error),
}

impl From<std::io::Error> for MapError {
    fn from(err: std::io::Error) -> Self {
        MapError::Io(err)
    }
}

impl From<Errno> for MapError {
    fn from(err: Errno) -> Self {
        MapError::Io(std::io::Error::from_raw_os_error(err as i32))
    }
}

impl MappedFile {
    pub fn new(f: &File) -> Result<Self, MapError> {
        let len: NonZeroUsize = NonZeroUsize::new(f.metadata()?.len().try_into().unwrap())
            .ok_or(MapError::ZeroLength)?;

        unsafe {
            let addr = mmap(None, len, ProtFlags::PROT_READ, MapFlags::MAP_SHARED, f.as_raw_fd(), 0)?;
            Ok(MappedFile {
                addr,
                len: len.into(),
            })
        }
    }

    pub fn data(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(self.addr as *const u8, self.len)
        }
    }
}

impl Drop for MappedFile {
    fn drop(&mut self) {
        unsafe {
            munmap(self.addr, self.len).expect("munmap failed");
        }
    }
}