This contains thin wrappers around memfd_create
and the associated file sealing API.
The MemFile
struct represents a file created by the memfd_create
syscall.
Such files are memory backed and fully anonymous, meaning no other process can see them (well... except by looking in /proc
on Linux).
After creation, the file descriptors can be shared with child processes, or even sent to another process over a Unix socket. The files can then be memory mapped to be used as shared memory.
This is all quite similar to shm_open
, except that files created by shm_open
are not anoynmous.
Depending on your application, the anonymous nature of memfd
may be a nice property.
Additionally, files created by shm_open
do not support file sealing.
Currently supported operating systems are:
- Linux
- Android
- FreeBSD
The Seal::FutureWrite
seal is only supported on Linux.
Please feel free to open a PR to add support for your favorite OS if it provides memfd_create
.
You can enable file sealing for MemFile
by creating them with CreateOptions::allow_sealing(true)
.
This allows you to use MemFile::add_seals
to add seals to the file.
You can also get the list of seals with MemFile::get_seals
.
Once a seal is added to a file, it can not be removed.
Each seal prevents certain types of actions on the file.
For example: the Seal::Write
seal prevents writing to the file, both through syscalls and memory mappings,
and the Seal::Shrink
and Seal::Grow
seals prevent the file from being resized.
This is quite interesting for Rust, as it is the only guaranteed safe way to map memory:
when a file is sealed with Seal::Write
and Seal::Shrink
, the file contents can not change, and the file can not be shrinked.
The latter is also important, because trying to read from a memory mapping a of file that was shrinked too far will raise a SIGBUS
signal
and likely crash your application.
Another interesting option is to first create a shared, writable memory mapping for your MemFile
,
and then add the Seal::FutureWrite
and Seal::Shrink
seals.
In that case, only the existing memory mapping can be used to change the contents of the file, even after the seals have been added.
When sharing the file with other processes, it prevents those processes from shrinking or writing to the file,
while the original process can still change the file contents.
use memfile::{MemFile, CreateOptions, Seal};
use std::io::Write;
let mut file = MemFile::create("foo", CreateOptions::new().allow_sealing(true))?;
file.write_all(b"Hello world!")?;
file.add_seals(Seal::Write | Seal::Shrink | Seal::Grow)?;
// From now on, all writes or attempts to created shared, writable memory mappings will fail.