1use std::{
4 io::{Read, Seek, SeekFrom, Write},
5 os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd},
6};
7
8use anyhow::{bail, Result};
9use memfd::{FileSeal, Memfd, MemfdOptions};
10
11pub struct Mfd(Memfd);
12
13pub enum Seals {
14 Unsealed,
16 Readable,
18 Writable,
20}
21
22impl Mfd {
23 pub fn create(name: &str) -> Result<Self> {
25 let opts = MemfdOptions::default().allow_sealing(true);
26 let mfd = opts.create(name)?;
27 Ok(Self(mfd))
28 }
29
30 pub fn read_all(&mut self) -> Result<Vec<u8>> {
32 self.0.as_file().seek(SeekFrom::Start(0))?;
33 let mut buf: Vec<u8> = Vec::new();
36 self.0.as_file().read_to_end(&mut buf)?;
37
38 Ok(buf)
39 }
40
41 pub fn write(&mut self, data: &[u8]) -> Result<()> {
43 self.0.as_file().seek(SeekFrom::Start(0))?;
44 self.0.as_file().set_len(0)?;
45 self.0.as_file().write_all(data)?;
46 Ok(())
47 }
48
49 pub fn finalize(&mut self, seals: Seals) -> Result<()> {
51 let file_seals: Vec<FileSeal> = match seals {
52 Seals::Unsealed => vec![],
53 Seals::Readable => vec![
54 FileSeal::SealShrink,
55 FileSeal::SealGrow,
56 FileSeal::SealWrite,
57 FileSeal::SealSeal,
58 ],
59 Seals::Writable => vec![FileSeal::SealSeal],
60 };
61
62 for seal in file_seals {
63 self.0.add_seal(seal)?;
64 }
65
66 Ok(())
67 }
68
69 pub fn from_fd(fd: OwnedFd) -> Result<Self> {
72 let fd = match Memfd::try_from_fd(fd) {
73 Ok(memfd) => memfd,
74 Err(_) => bail!("cannot get Memfd from RawFd"),
75 };
76 Ok(Self(fd))
77 }
78}
79
80impl AsFd for Mfd {
81 fn as_fd(&self) -> BorrowedFd<'_> {
82 self.0.as_file().as_fd()
83 }
84}
85
86impl AsRawFd for Mfd {
87 fn as_raw_fd(&self) -> RawFd {
88 self.0.as_raw_fd()
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn test_mfd() {
98 let mut mfd = Mfd::create("test").unwrap();
99 mfd.write("Hello, world!".as_bytes()).unwrap();
100 mfd.finalize(Seals::Readable).unwrap();
101
102 assert_eq!(mfd.read_all().unwrap(), "Hello, world!".as_bytes());
103 }
104}