1use crate::sealing;
2use rustix::fs::{MemfdFlags, SealFlags};
3use std::fs;
4use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
5
6#[derive(Clone, Debug)]
8pub struct MemfdOptions {
9 allow_sealing: bool,
10 cloexec: bool,
11 hugetlb: Option<HugetlbSize>,
12}
13
14impl MemfdOptions {
15 pub const fn new() -> Self {
24 Self {
25 allow_sealing: false,
26 cloexec: true,
27 hugetlb: None,
28 }
29 }
30
31 pub const fn allow_sealing(mut self, value: bool) -> Self {
33 self.allow_sealing = value;
34 self
35 }
36
37 pub const fn close_on_exec(mut self, value: bool) -> Self {
39 self.cloexec = value;
40 self
41 }
42
43 pub const fn hugetlb(mut self, size: Option<HugetlbSize>) -> Self {
45 self.hugetlb = size;
46 self
47 }
48
49 fn bitflags(&self) -> MemfdFlags {
51 let mut bits = MemfdFlags::empty();
52 if self.allow_sealing {
53 bits |= MemfdFlags::ALLOW_SEALING;
54 }
55 if self.cloexec {
56 bits |= MemfdFlags::CLOEXEC;
57 }
58 if let Some(ref hugetlb) = self.hugetlb {
59 bits |= hugetlb.bitflags();
60 bits |= MemfdFlags::HUGETLB;
61 }
62 bits
63 }
64
65 pub fn create<T: AsRef<str>>(&self, name: T) -> Result<Memfd, crate::Error> {
69 let flags = self.bitflags();
70 let fd = rustix::fs::memfd_create(name.as_ref(), flags)
71 .map_err(Into::into)
72 .map_err(crate::Error::Create)?;
73 Ok(Memfd { file: fd.into() })
74 }
75}
76
77impl Default for MemfdOptions {
78 fn default() -> Self {
79 Self::new()
80 }
81}
82
83#[derive(Copy, Clone, Debug)]
85pub enum HugetlbSize {
86 Huge64KB,
88 Huge512KB,
90 Huge1MB,
92 Huge2MB,
94 Huge8MB,
96 Huge16MB,
98 Huge256MB,
100 Huge1GB,
102 Huge2GB,
104 Huge16GB,
106}
107
108impl HugetlbSize {
109 const fn bitflags(self) -> MemfdFlags {
110 match self {
111 Self::Huge64KB => MemfdFlags::HUGE_64KB,
112 Self::Huge512KB => MemfdFlags::HUGE_512KB,
113 Self::Huge1MB => MemfdFlags::HUGE_1MB,
114 Self::Huge2MB => MemfdFlags::HUGE_2MB,
115 Self::Huge8MB => MemfdFlags::HUGE_8MB,
116 Self::Huge16MB => MemfdFlags::HUGE_16MB,
117 Self::Huge256MB => MemfdFlags::HUGE_256MB,
118 Self::Huge1GB => MemfdFlags::HUGE_1GB,
119 Self::Huge2GB => MemfdFlags::HUGE_2GB,
120 Self::Huge16GB => MemfdFlags::HUGE_16GB,
121 }
122 }
123}
124
125#[derive(Debug)]
127pub struct Memfd {
128 file: fs::File,
129}
130
131impl Memfd {
132 pub fn try_from_fd<F>(fd: F) -> Result<Self, F>
138 where
139 F: AsRawFd + IntoRawFd,
140 {
141 if is_memfd(&fd) {
142 let file = unsafe { fs::File::from_raw_fd(fd.into_raw_fd()) };
145 Ok(Self { file })
146 } else {
147 Err(fd)
148 }
149 }
150
151 pub fn try_from_file(file: fs::File) -> Result<Self, fs::File> {
159 Self::try_from_fd(file)
160 }
161
162 pub const fn as_file(&self) -> &fs::File {
166 &self.file
167 }
168
169 pub fn into_file(self) -> fs::File {
173 self.file
174 }
175
176 pub fn seals(&self) -> Result<sealing::SealsHashSet, crate::Error> {
178 let flags = Self::file_get_seals(&self.file)?;
179 Ok(sealing::bitflags_to_seals(flags))
180 }
181
182 pub fn add_seal(&self, seal: sealing::FileSeal) -> Result<(), crate::Error> {
184 let flags = seal.bitflags();
185 self.add_seal_flags(flags)
186 }
187
188 pub fn add_seals<'a>(
190 &self,
191 seals: impl IntoIterator<Item = &'a sealing::FileSeal>,
192 ) -> Result<(), crate::Error> {
193 let flags = sealing::seals_to_bitflags(seals);
194 self.add_seal_flags(flags)
195 }
196
197 fn add_seal_flags(&self, flags: rustix::fs::SealFlags) -> Result<(), crate::Error> {
198 rustix::fs::fcntl_add_seals(&self.file, flags)
199 .map_err(Into::into)
200 .map_err(crate::Error::AddSeals)?;
201 Ok(())
202 }
203
204 fn file_get_seals(fp: &fs::File) -> Result<SealFlags, crate::Error> {
206 let r = rustix::fs::fcntl_get_seals(fp)
207 .map_err(Into::into)
208 .map_err(crate::Error::GetSeals)?;
209 Ok(r)
210 }
211}
212
213impl FromRawFd for Memfd {
214 unsafe fn from_raw_fd(fd: RawFd) -> Self {
225 let file = fs::File::from_raw_fd(fd);
226 Self { file }
227 }
228}
229
230impl AsRawFd for Memfd {
231 fn as_raw_fd(&self) -> RawFd {
232 self.file.as_raw_fd()
233 }
234}
235
236impl IntoRawFd for Memfd {
237 fn into_raw_fd(self) -> RawFd {
238 self.into_file().into_raw_fd()
239 }
240}
241
242fn is_memfd<F: AsRawFd>(fd: &F) -> bool {
247 let fd = unsafe { rustix::fd::BorrowedFd::borrow_raw(fd.as_raw_fd()) };
251 rustix::fs::fcntl_get_seals(fd).is_ok()
252}