mapped_file/file/
memory.rs1use super::*;
6use libc::{
7 c_uint,
8 memfd_create,
9 MFD_CLOEXEC,
10 MFD_HUGETLB,
11
12 ftruncate,
13};
14use std::{
15 ffi::CStr,
16 borrow::{
17 Borrow,
18 BorrowMut,
19 },
20 ops,
21};
22use hugetlb::{
23 MapHugeFlag,
24 HugePage,
25};
26
27static UNNAMED: &'static CStr = unsafe {
28 CStr::from_bytes_with_nul_unchecked(b"<unnamed memory file>\0")
29};
30
31const DEFAULT_FLAGS: c_uint = MFD_CLOEXEC;
32
33#[inline(always)]
34pub unsafe fn create_raw(name: impl AsRef<CStr>, flags: c_uint) -> io::Result<UnmanagedFD>
40{
41 UnmanagedFD::new_raw(memfd_create(name.as_ref().as_ptr(), flags)).ok_or_else(|| io::Error::last_os_error())
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
46#[repr(transparent)]
47pub struct MemoryFile(ManagedFD);
48
49#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
51pub struct NamedMemoryFile(Box<CStr>, MemoryFile);
52
53impl Borrow<MemoryFile> for NamedMemoryFile
54{
55 #[inline]
56 fn borrow(&self) -> &MemoryFile {
57 &self.1
58 }
59}
60impl BorrowMut<MemoryFile> for NamedMemoryFile
61{
62 #[inline]
63 fn borrow_mut(&mut self) -> &mut MemoryFile {
64 &mut self.1
65 }
66}
67impl ops::DerefMut for NamedMemoryFile
68{
69 fn deref_mut(&mut self) -> &mut Self::Target {
70 &mut self.1
71 }
72}
73impl ops::Deref for NamedMemoryFile
74{
75 type Target = MemoryFile;
76 #[inline]
77 fn deref(&self) -> &Self::Target {
78 &self.1
79 }
80}
81
82impl MemoryFile
84{
85 pub fn new() -> io::Result<Self>
87 {
88 let managed = unsafe {
89 match memfd_create(UNNAMED.as_ptr(), DEFAULT_FLAGS) {
90 -1 => return Err(io::Error::last_os_error()),
91 fd => ManagedFD::take_unchecked(fd),
92 }
93 };
94 Ok(Self(managed))
95 }
96 #[inline]
97 pub fn resize(&mut self, value: usize) -> io::Result<()>
98 {
99 if 0 == unsafe { ftruncate(self.as_raw_fd(), value.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?) } {
100 Ok(())
101 } else {
102 Err(io::Error::last_os_error())
103 }
104 }
105
106 pub fn with_hugetlb(hugetlb: MapHugeFlag) -> io::Result<Self>
107 {
108 unsafe { create_raw(UNNAMED, DEFAULT_FLAGS | (hugetlb.get_mask() as c_uint)) }
109 .map(ManagedFD::take)
110 .map(Self)
111 }
112
113 pub fn with_size(size: usize) -> io::Result<Self>
114 {
115 let mut this = Self(unsafe { create_raw(UNNAMED, DEFAULT_FLAGS) }.map(ManagedFD::take)?);
116 this.resize(size)?;
117 Ok(this)
118 }
119
120 #[inline]
121 pub fn with_size_hugetlb(size: usize, hugetlb: MapHugeFlag) -> io::Result<Self>
122 {
123 let mut this = Self::with_hugetlb(hugetlb)?;
124 this.resize(size)?;
125 Ok(this)
126 }
127}
128
129fn alloc_cstring(string: &str) -> std::ffi::CString
130{
131 #[cold]
132 fn _contains_nul(mut bytes: Vec<u8>) -> std::ffi::CString
133 {
134 let len = unsafe {
136 memchr::memchr(0, &bytes[..]).unwrap_unchecked()
137 };
138 bytes.truncate(len);
139 unsafe {
141 std::ffi::CString::from_vec_with_nul_unchecked(bytes)
142 }
143 }
144 let mut bytes = Vec::with_capacity(string.len()+1);
145 bytes.extend_from_slice(string.as_bytes());
146 bytes.push(0);
147 match std::ffi::CString::from_vec_with_nul(bytes) {
148 Ok(v) => v,
149 Err(cn) => {
150 _contains_nul(cn.into_bytes())
151 }
152 }
153}
154
155impl NamedMemoryFile
156{
157 #[inline]
158 pub fn new(name: impl AsRef<str>) -> io::Result<Self>
159 {
160 let name: Box<CStr> = alloc_cstring(name.as_ref()).into();
161 let managed = unsafe {
162 match memfd_create(name.as_ptr(), DEFAULT_FLAGS) {
163 -1 => return Err(io::Error::last_os_error()),
164 fd => ManagedFD::take_unchecked(fd),
165 }
166 };
167 Ok(Self(name, MemoryFile(managed)))
168 }
169
170 pub fn with_hugetlb(name: impl AsRef<str>, hugetlb: MapHugeFlag) -> io::Result<Self>
171 {
172 let name: Box<CStr> = alloc_cstring(name.as_ref()).into();
173 let memfd = MemoryFile(unsafe { create_raw(&name, DEFAULT_FLAGS | (hugetlb.get_mask() as c_uint)) }
174 .map(ManagedFD::take)?);
175 Ok(Self(name, memfd))
176 }
177
178 pub fn with_size(name: impl AsRef<str>, size: usize) -> io::Result<Self>
179 {
180 let name: Box<CStr> = alloc_cstring(name.as_ref()).into();
181 let mut this = MemoryFile(unsafe { create_raw(&name, DEFAULT_FLAGS) }.map(ManagedFD::take)?);
182 this.resize(size)?;
183 Ok(Self(name, this))
184 }
185
186 #[inline]
187 pub fn with_size_hugetlb(name: impl AsRef<str>, size: usize, hugetlb: MapHugeFlag) -> io::Result<Self>
188 {
189 let mut this = Self::with_hugetlb(name, hugetlb)?;
190 this.resize(size)?;
191 Ok(this)
192 }
193}
194
195impl AsRawFd for MemoryFile
196{
197 #[inline]
198 fn as_raw_fd(&self) -> RawFd {
199 self.0.as_raw_fd()
200 }
201}
202
203impl FromRawFd for MemoryFile
204{
205 #[inline]
206 unsafe fn from_raw_fd(fd: RawFd) -> Self {
207 Self(ManagedFD::from_raw_fd(fd))
208 }
209}
210
211impl IntoRawFd for MemoryFile
212{
213 #[inline]
214 fn into_raw_fd(self) -> RawFd {
215 self.0.into_raw_fd()
216 }
217}
218
219impl From<MemoryFile> for ManagedFD
220{
221 #[inline]
222 fn from(from: MemoryFile) -> Self
223 {
224 from.0
225 }
226}
227
228impl From<MemoryFile> for std::fs::File
229{
230 #[inline]
231 fn from(from: MemoryFile) -> Self
232 {
233 from.0.into()
234 }
235}
236
237raw::impl_io_for_fd!(MemoryFile => .0.as_raw_fd());