pub mod mmap {
pub use memmap2::*;
}
pub mod mfd {
pub use memfd::*;
}
use super::Error;
fn verify_seal(memfd: &mfd::Memfd, seal: mfd::FileSeal) -> Result<(), Error> {
let seals = memfd.seals()?;
if seals.contains(&seal) {
return Ok(());
}
memfd.add_seal(seal)?;
Ok(())
}
pub fn read_memfd(memfd: &mfd::Memfd) -> Result<mmap::Mmap, Error> {
verify_seal(&memfd, mfd::FileSeal::SealShrink)?;
verify_seal(&memfd, mfd::FileSeal::SealWrite)?;
let r = unsafe { mmap::MmapOptions::new().map_copy_read_only(memfd.as_file()) }?;
Ok(r)
}
pub fn raw_memfd(memfd: &mfd::Memfd, len: usize) -> Result<mmap::MmapRaw, Error> {
verify_seal(&memfd, mfd::FileSeal::SealShrink)?;
Ok(mmap::MmapOptions::new().len(len).map_raw(memfd.as_file())?)
}
pub fn write_once<F: FnOnce(&mut [u8])>(size: u64, name: &str, f: F) -> Result<mfd::Memfd, Error> {
let opts = memfd::MemfdOptions::new().allow_sealing(true).close_on_exec(true);
let mut h = mfd::SealsHashSet::new();
h.insert(mfd::FileSeal::SealGrow);
h.insert(mfd::FileSeal::SealShrink);
h.insert(mfd::FileSeal::SealSeal);
h.insert(mfd::FileSeal::SealWrite);
write_once_custom(size, name, opts, &h, f)
}
pub fn write_once_custom<F: FnOnce(&mut [u8])>(
size: u64, name: &str, memfd_options: memfd::MemfdOptions, seals: &mfd::SealsHashSet, f: F,
) -> Result<mfd::Memfd, Error> {
let memfd = memfd_options.create(name)?;
memfd.as_file().set_len(size)?;
let mut m = unsafe { mmap::MmapMut::map_mut(memfd.as_file())? };
f(&mut m);
drop(m);
if !seals.is_empty() {
memfd.add_seals(seals)?;
}
Ok(memfd)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_mmap() -> Result<(), Error> {
let opts = mfd::MemfdOptions::default().allow_sealing(true);
let memfd = opts.create("test-ro")?;
memfd.as_file().set_len(16384)?;
let mmap = read_memfd(&memfd)?;
assert!(memfd.seals()?.contains(&mfd::FileSeal::SealShrink));
assert!(memfd.seals()?.contains(&mfd::FileSeal::SealWrite));
assert_eq!(mmap.len(), 16384);
assert!(raw_memfd(&memfd, 16384).is_err());
Ok(())
}
#[test]
fn create_mmap_raw() -> Result<(), Error> {
let opts = mfd::MemfdOptions::default().allow_sealing(true);
let memfd = opts.create("test-raw")?;
memfd.as_file().set_len(16384)?;
let mmap_raw = raw_memfd(&memfd, 16384)?;
assert_eq!(mmap_raw.len(), 16384);
assert!(read_memfd(&memfd).is_err());
Ok(())
}
#[test]
fn write_then_read() -> Result<(), Error> {
let m = write_once(4096, "write_then_read_test", |x| {
assert_eq!(x.len(), 4096);
assert_eq!(x[5], 0);
x[2049] = 100;
})?;
let m2 = read_memfd(&m)?;
assert_eq!(m2[2049], 100);
assert_eq!(m2[465], 0);
Ok(())
}
}