|
|
|
@ -11,7 +11,7 @@ use std::{
|
|
|
|
|
self,
|
|
|
|
|
MaybeUninit,
|
|
|
|
|
},
|
|
|
|
|
borrow::BorrowMut,
|
|
|
|
|
borrow::{BorrowMut, Cow},
|
|
|
|
|
convert::{TryFrom, TryInto,},
|
|
|
|
|
};
|
|
|
|
|
use libc::{
|
|
|
|
@ -166,9 +166,11 @@ fn translate_hugetlb_size(size: usize) -> mapped_file::hugetlb::HugePage
|
|
|
|
|
.or_else(|| sizes_kb.iter().nth(1)
|
|
|
|
|
.or_else(|| sizes_kb.first()))
|
|
|
|
|
}
|
|
|
|
|
const MB: usize = 1024*1024;
|
|
|
|
|
const GB: usize = 1024 * MB;
|
|
|
|
|
match size {
|
|
|
|
|
0..(1024*1024) => mapped_file::hugetlb::HugePage::Smallest,
|
|
|
|
|
(1024*1024)..(1024*1024*1024) => mapped_file::hugetlb::HugePage::Selected(check_func),
|
|
|
|
|
0..MB => mapped_file::hugetlb::HugePage::Smallest,
|
|
|
|
|
MB..GB => mapped_file::hugetlb::HugePage::Selected(check_func),
|
|
|
|
|
very_high => mapped_file::hugetlb::HugePage::Largest,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -191,6 +193,194 @@ fn create_sized_temp_mapping(size: usize) -> io::Result<(MappedFile<MemoryFile>,
|
|
|
|
|
MappedFile::new(file, size, Perm::ReadWrite, Flags::Shared).map(|x| (x, false))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type MappedMemoryFile = MappedFile<mapped_file::file::memory::MemoryFile>;
|
|
|
|
|
|
|
|
|
|
/// How a mapped operation should optimally take place
|
|
|
|
|
//TODO: Make optimised mapping operations for each one, like `fn process(self, enc: &mut Crypter) -> io::Result<usize>`
|
|
|
|
|
pub enum OpTable<T, U>
|
|
|
|
|
{
|
|
|
|
|
/// Both input and output are mapped
|
|
|
|
|
Both(MappedFile<T>, MappedFile<U>),
|
|
|
|
|
/// Input is mapped, but output is not. Work is done through a temporary map, then copied to `U`.
|
|
|
|
|
Input(MappedFile<T>, MappedMemoryFile, U),
|
|
|
|
|
/// Output is mapped, but input is not. Work is done from a temporary map
|
|
|
|
|
Output(T, MappedMemoryFile, MappedFile<U>),
|
|
|
|
|
/// Streaming mode (`read()`+`write()` only)
|
|
|
|
|
Neither(T, U),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T, U> OpTable<T, U>
|
|
|
|
|
{
|
|
|
|
|
/// Consume into either a mapping line, or the in/out tuple if neither are mapped.
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn only_mapped(self) -> Result<Self, (T, U)>
|
|
|
|
|
{
|
|
|
|
|
match self {
|
|
|
|
|
Self::Neither(t, u) => Err((t, u)),
|
|
|
|
|
this => Ok(this),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: io::Read+AsRawFd, U: io::Write+AsRawFd> OpTable<T, U>
|
|
|
|
|
{
|
|
|
|
|
fn pre_process(&mut self) -> io::Result<()>
|
|
|
|
|
{
|
|
|
|
|
match self {
|
|
|
|
|
Self::Both(input, output)
|
|
|
|
|
=> {
|
|
|
|
|
let _ = input.advise(mapped_file::Advice::Sequential, Some(true));
|
|
|
|
|
let _ = output.advise(mapped_file::Advice::Sequential, None);
|
|
|
|
|
},
|
|
|
|
|
Self::Input(input, mem)
|
|
|
|
|
=> {
|
|
|
|
|
let _ = input.advise(mapped_file::Advice::Sequential, Some(true));
|
|
|
|
|
let _ = mem.advise(mapped_file::Advice::Sequential, None);
|
|
|
|
|
},
|
|
|
|
|
Self::Output(input, mem, _)
|
|
|
|
|
=> {
|
|
|
|
|
let _ = mem.advise(mapped_file::Advice::Sequential, Some(true));
|
|
|
|
|
std::io::copy(&mut input, &mut mem)?;
|
|
|
|
|
},
|
|
|
|
|
_ => (),
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
fn post_process(&mut self) -> io::Result<()>
|
|
|
|
|
{
|
|
|
|
|
match self {
|
|
|
|
|
Self::Both(_, output) => drop(output.flush(mapped_file::Flush::Wait)?),
|
|
|
|
|
Self::Input(_, mut mem, mut output) => drop(std::io::copy(&mut mem, &mut output)?),
|
|
|
|
|
Self::Output(_, _, mut output) => drop(output.flush(mapped_file::Flush::Wait)?),
|
|
|
|
|
Self::Neither(_, stream) => stream.flush()?,
|
|
|
|
|
_ => (),
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
/// Execute this en/decryption in an optimised function
|
|
|
|
|
pub fn execute(mut self, mut mode: impl BorrowMut<Crypter>) -> io::Result<usize>
|
|
|
|
|
{
|
|
|
|
|
self.pre_process()?;
|
|
|
|
|
let mode: &mut Crypter = mode.borrow_mut();
|
|
|
|
|
match self {
|
|
|
|
|
Self::Both(mut input, mut output) => {
|
|
|
|
|
let len = std::cmp::min(input.len(), output.len());
|
|
|
|
|
process_mapped_files(mode, &mut input, &mut output)?;
|
|
|
|
|
|
|
|
|
|
self.post_process()?;
|
|
|
|
|
Ok(len)
|
|
|
|
|
},
|
|
|
|
|
Self::Input(mut input, mut output, _) => {
|
|
|
|
|
let len = std::cmp::min(input.len(), output.len());
|
|
|
|
|
process_mapped_files(mode, &mut input, &mut output)?;
|
|
|
|
|
|
|
|
|
|
self.post_process()?;
|
|
|
|
|
Ok(len)
|
|
|
|
|
},
|
|
|
|
|
Self::Output(_, mut input, mut output) => {
|
|
|
|
|
let len = std::cmp::min(input.len(), output.len());
|
|
|
|
|
process_mapped_files(mode, &mut input, &mut output)?;
|
|
|
|
|
|
|
|
|
|
self.post_process()?;
|
|
|
|
|
Ok(len)
|
|
|
|
|
},
|
|
|
|
|
Self::Neither(sin, sout) => {
|
|
|
|
|
const BUFFER_SIZE: usize = 1024*1024;
|
|
|
|
|
macro_rules! try_allocmem {
|
|
|
|
|
($size:expr) => {
|
|
|
|
|
{
|
|
|
|
|
let size = usize::from($size);
|
|
|
|
|
let hsz = mapped_file::hugetlb::HugePage::Dynamic { kilobytes: size/1024 }; // 1MB buffer
|
|
|
|
|
hsz.compute_huge()
|
|
|
|
|
.and_then(|huge| mapped_file::file::memory::MemoryFile::with_size_hugetlb(size, huge).ok())
|
|
|
|
|
.or_else(|| mapped_file::file::memory::MemoryFile::with_size(size).ok())
|
|
|
|
|
.and_then(|file| MappedFile::new(file, size, Perm::ReadWrite, Flags::Private).ok())
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
($mem:expr, $size:expr) => {
|
|
|
|
|
$mem.map(|x| Cow::Borrowed(&mut x[..])).unwrap_or_else(|| Cow::Owned(vec![0u8; $size]));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let mut _mem = try_allocmem!(BUFFER_SIZE);
|
|
|
|
|
let mut _memo = try_allocmem!(BUFFER_SIZE);
|
|
|
|
|
let mut buffer = try_allocmem!(_mem, BUFFER_SIZE);
|
|
|
|
|
let mut buffero = try_allocmem!(_memo, BUFFER_SIZE);
|
|
|
|
|
let mut read =0;
|
|
|
|
|
let mut cur;
|
|
|
|
|
while { cur = sin.read(&mut buffer[..])?; cur > 0 } {
|
|
|
|
|
/*let cur =*/ mode.update(&buffer[..cur], &mut buffero[..cur])?;
|
|
|
|
|
sout.write_all(&buffero[..cur])?;
|
|
|
|
|
read += cur;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.post_process()?;
|
|
|
|
|
Ok(read)
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn sized_then_or<T: AsRawFd, U, F>(stream: T, trans: F) -> Result<U, T>
|
|
|
|
|
where F: FnOnce(T, usize) -> U
|
|
|
|
|
{
|
|
|
|
|
let Some(size): usize = raw_file_size(&stream).and_then(u64::into).ok() else { return Err(stream); };
|
|
|
|
|
Some(trans(stream, trans))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn map_size_or<T: AsRawFd, U, F>(stream: T, size: usize, trans: F) -> Result<U, T>
|
|
|
|
|
where F: FnOnce(MappedFile<T>, usize) -> U
|
|
|
|
|
{
|
|
|
|
|
if try_map_to(&stream, size) {
|
|
|
|
|
// Sized
|
|
|
|
|
match MappedFile::try_new(stream, size, Perm::ReadWrite, Flags::Shared) {
|
|
|
|
|
Ok(map) => Ok(trans(map, size)),
|
|
|
|
|
Err(e) => Err(e.into_inner()),
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Unsized
|
|
|
|
|
Err(stream)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create an optimised call table for the cryptographic transformation from `from` to `to`.
|
|
|
|
|
pub fn create_process<T: AsRawFd, U: AsRawFd>(from: T, to: U) -> OpTable<T, U>
|
|
|
|
|
{
|
|
|
|
|
let (input, buffsz) = match sized_then_or(from, |input, input_size| {
|
|
|
|
|
(match MappedFile::try_new(input, input_size, Perm::Readonly, Flags::Private) {
|
|
|
|
|
Ok(m) => Ok(m),
|
|
|
|
|
Err(e) => Err(e.into_inner()),
|
|
|
|
|
}, input_size)
|
|
|
|
|
}) {
|
|
|
|
|
Ok((i, bs)) => (i, Some(bs)),
|
|
|
|
|
Err(e) => (Err(e), None),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let (output, outsz) = {
|
|
|
|
|
if let Some(buffsz) = buffsz.or_else(|| raw_file_size(&to).ok()) {
|
|
|
|
|
match map_size_or(to, buffsz, |mmap, size| {
|
|
|
|
|
(mmap, size)
|
|
|
|
|
}) {
|
|
|
|
|
Ok((m, s)) => (Ok(m), Some(s)),
|
|
|
|
|
Err(e) => (Err(e), if buffsz == 0 { None } else { Some(buffsz) }),
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Err((to, None))
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
match ((input, buffsz), (output, outsz)) {
|
|
|
|
|
// Check for all combinations of mapping successes or failures
|
|
|
|
|
((Ok(min), isz), (Ok(mout), osz)) => OpTable::Both(min, mout),
|
|
|
|
|
((Ok(min), isz), (Err(sout), osz)) => OpTable::Input(min, create_sized_temp_mapping(isz.or(osz)), sout),
|
|
|
|
|
((Err(sin), isz), (Ok(mout), osz)) => OpTable::Output(sin, create_sized_temp_mapping(osz.or(isz)), mout),
|
|
|
|
|
((Err(sin, isz), (Err(sout), osz))) => OpTable::Neither(sin, sout),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature="try_process-old")]
|
|
|
|
|
const _:() = {
|
|
|
|
|
pub fn try_process(mut mode: impl BorrowMut<Crypter>) -> io::Result<io::Result<()>>
|
|
|
|
|
{
|
|
|
|
|
let mode = mode.borrow_mut();
|
|
|
|
@ -286,3 +476,4 @@ pub fn try_process(mut mode: impl BorrowMut<Crypter>) -> io::Result<io::Result<(
|
|
|
|
|
//todo!("Try to map the stdin and stdout streams, if that fails, return Err(last_os_err).");
|
|
|
|
|
//todo!("return Ok(process_mapped_files(mode, mstdin, mstdout, key, iv))")
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|