1 | //! A cross-platform Rust API for memory mapped buffers. |
2 | |
3 | #![doc (html_root_url = "https://docs.rs/memmap2/0.2.3" )] |
4 | |
5 | #[cfg (windows)] |
6 | mod windows; |
7 | #[cfg (windows)] |
8 | use windows::MmapInner; |
9 | |
10 | #[cfg (unix)] |
11 | mod unix; |
12 | #[cfg (unix)] |
13 | use unix::MmapInner; |
14 | |
15 | #[cfg (not(any(unix, windows)))] |
16 | mod stub; |
17 | #[cfg (not(any(unix, windows)))] |
18 | use crate::stub::MmapInner; |
19 | |
20 | use std::fmt; |
21 | use std::fs::File; |
22 | use std::io::{Error, ErrorKind, Result}; |
23 | use std::ops::{Deref, DerefMut}; |
24 | use std::slice; |
25 | use std::usize; |
26 | |
27 | /// A memory map builder, providing advanced options and flags for specifying memory map behavior. |
28 | /// |
29 | /// `MmapOptions` can be used to create an anonymous memory map using [`map_anon()`], or a |
30 | /// file-backed memory map using one of [`map()`], [`map_mut()`], [`map_exec()`], |
31 | /// [`map_copy()`], or [`map_copy_read_only()`]. |
32 | /// |
33 | /// ## Safety |
34 | /// |
35 | /// All file-backed memory map constructors are marked `unsafe` because of the potential for |
36 | /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or |
37 | /// out of process. Applications must consider the risk and take appropriate precautions when |
38 | /// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g. |
39 | /// unlinked) files exist but are platform specific and limited. |
40 | /// |
41 | /// [`map_anon()`]: MmapOptions::map_anon() |
42 | /// [`map()`]: MmapOptions::map() |
43 | /// [`map_mut()`]: MmapOptions::map_mut() |
44 | /// [`map_exec()`]: MmapOptions::map_exec() |
45 | /// [`map_copy()`]: MmapOptions::map_copy() |
46 | /// [`map_copy_read_only()`]: MmapOptions::map_copy_read_only() |
47 | #[derive (Clone, Debug, Default)] |
48 | pub struct MmapOptions { |
49 | offset: u64, |
50 | len: Option<usize>, |
51 | stack: bool, |
52 | populate: bool, |
53 | } |
54 | |
55 | impl MmapOptions { |
56 | /// Creates a new set of options for configuring and creating a memory map. |
57 | /// |
58 | /// # Example |
59 | /// |
60 | /// ``` |
61 | /// use memmap2::{MmapMut, MmapOptions}; |
62 | /// # use std::io::Result; |
63 | /// |
64 | /// # fn main() -> Result<()> { |
65 | /// // Create a new memory map builder. |
66 | /// let mut mmap_options = MmapOptions::new(); |
67 | /// |
68 | /// // Configure the memory map builder using option setters, then create |
69 | /// // a memory map using one of `mmap_options.map_anon`, `mmap_options.map`, |
70 | /// // `mmap_options.map_mut`, `mmap_options.map_exec`, or `mmap_options.map_copy`: |
71 | /// let mut mmap: MmapMut = mmap_options.len(36).map_anon()?; |
72 | /// |
73 | /// // Use the memory map: |
74 | /// mmap.copy_from_slice(b"...data to copy to the memory map..." ); |
75 | /// # Ok(()) |
76 | /// # } |
77 | /// ``` |
78 | pub fn new() -> MmapOptions { |
79 | MmapOptions::default() |
80 | } |
81 | |
82 | /// Configures the memory map to start at byte `offset` from the beginning of the file. |
83 | /// |
84 | /// This option has no effect on anonymous memory maps. |
85 | /// |
86 | /// By default, the offset is 0. |
87 | /// |
88 | /// # Example |
89 | /// |
90 | /// ``` |
91 | /// use memmap2::MmapOptions; |
92 | /// use std::fs::File; |
93 | /// |
94 | /// # fn main() -> std::io::Result<()> { |
95 | /// let mmap = unsafe { |
96 | /// MmapOptions::new() |
97 | /// .offset(30) |
98 | /// .map(&File::open("LICENSE-APACHE" )?)? |
99 | /// }; |
100 | /// assert_eq!(&b"Apache License" [..], |
101 | /// &mmap[..14]); |
102 | /// # Ok(()) |
103 | /// # } |
104 | /// ``` |
105 | pub fn offset(&mut self, offset: u64) -> &mut Self { |
106 | self.offset = offset; |
107 | self |
108 | } |
109 | |
110 | /// Configures the created memory mapped buffer to be `len` bytes long. |
111 | /// |
112 | /// This option is mandatory for anonymous memory maps. |
113 | /// |
114 | /// For file-backed memory maps, the length will default to the file length. |
115 | /// |
116 | /// # Example |
117 | /// |
118 | /// ``` |
119 | /// use memmap2::MmapOptions; |
120 | /// use std::fs::File; |
121 | /// |
122 | /// # fn main() -> std::io::Result<()> { |
123 | /// let mmap = unsafe { |
124 | /// MmapOptions::new() |
125 | /// .len(9) |
126 | /// .map(&File::open("README.md" )?)? |
127 | /// }; |
128 | /// assert_eq!(&b"# memmap2" [..], &mmap[..]); |
129 | /// # Ok(()) |
130 | /// # } |
131 | /// ``` |
132 | pub fn len(&mut self, len: usize) -> &mut Self { |
133 | self.len = Some(len); |
134 | self |
135 | } |
136 | |
137 | /// Returns the configured length, or the length of the provided file. |
138 | fn get_len(&self, file: &File) -> Result<usize> { |
139 | self.len.map(Ok).unwrap_or_else(|| { |
140 | let len = file.metadata()?.len() - self.offset; |
141 | if len > (usize::MAX as u64) { |
142 | return Err(Error::new( |
143 | ErrorKind::InvalidData, |
144 | "memory map length overflows usize" , |
145 | )); |
146 | } |
147 | Ok(len as usize) |
148 | }) |
149 | } |
150 | |
151 | /// Configures the anonymous memory map to be suitable for a process or thread stack. |
152 | /// |
153 | /// This option corresponds to the `MAP_STACK` flag on Linux. It has no effect on Windows. |
154 | /// |
155 | /// This option has no effect on file-backed memory maps. |
156 | /// |
157 | /// # Example |
158 | /// |
159 | /// ``` |
160 | /// use memmap2::MmapOptions; |
161 | /// |
162 | /// # fn main() -> std::io::Result<()> { |
163 | /// let stack = MmapOptions::new().stack().len(4096).map_anon(); |
164 | /// # Ok(()) |
165 | /// # } |
166 | /// ``` |
167 | pub fn stack(&mut self) -> &mut Self { |
168 | self.stack = true; |
169 | self |
170 | } |
171 | |
172 | /// Populate (prefault) page tables for a mapping. |
173 | /// |
174 | /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later. |
175 | /// |
176 | /// This option corresponds to the `MAP_POPULATE` flag on Linux. It has no effect on Windows. |
177 | /// |
178 | /// # Example |
179 | /// |
180 | /// ``` |
181 | /// use memmap2::MmapOptions; |
182 | /// use std::fs::File; |
183 | /// |
184 | /// # fn main() -> std::io::Result<()> { |
185 | /// let file = File::open("LICENSE-MIT" )?; |
186 | /// |
187 | /// let mmap = unsafe { |
188 | /// MmapOptions::new().populate().map(&file)? |
189 | /// }; |
190 | /// |
191 | /// assert_eq!(&b"Copyright" [..], &mmap[..9]); |
192 | /// # Ok(()) |
193 | /// # } |
194 | /// ``` |
195 | pub fn populate(&mut self) -> &mut Self { |
196 | self.populate = true; |
197 | self |
198 | } |
199 | |
200 | /// Creates a read-only memory map backed by a file. |
201 | /// |
202 | /// # Errors |
203 | /// |
204 | /// This method returns an error when the underlying system call fails, which can happen for a |
205 | /// variety of reasons, such as when the file is not open with read permissions. |
206 | /// |
207 | /// # Example |
208 | /// |
209 | /// ``` |
210 | /// use memmap2::MmapOptions; |
211 | /// use std::fs::File; |
212 | /// use std::io::Read; |
213 | /// |
214 | /// # fn main() -> std::io::Result<()> { |
215 | /// let mut file = File::open("LICENSE-APACHE" )?; |
216 | /// |
217 | /// let mut contents = Vec::new(); |
218 | /// file.read_to_end(&mut contents)?; |
219 | /// |
220 | /// let mmap = unsafe { |
221 | /// MmapOptions::new().map(&file)? |
222 | /// }; |
223 | /// |
224 | /// assert_eq!(&contents[..], &mmap[..]); |
225 | /// # Ok(()) |
226 | /// # } |
227 | /// ``` |
228 | pub unsafe fn map(&self, file: &File) -> Result<Mmap> { |
229 | MmapInner::map(self.get_len(file)?, file, self.offset, self.populate) |
230 | .map(|inner| Mmap { inner }) |
231 | } |
232 | |
233 | /// Creates a readable and executable memory map backed by a file. |
234 | /// |
235 | /// # Errors |
236 | /// |
237 | /// This method returns an error when the underlying system call fails, which can happen for a |
238 | /// variety of reasons, such as when the file is not open with read permissions. |
239 | pub unsafe fn map_exec(&self, file: &File) -> Result<Mmap> { |
240 | MmapInner::map_exec(self.get_len(file)?, file, self.offset, self.populate) |
241 | .map(|inner| Mmap { inner }) |
242 | } |
243 | |
244 | /// Creates a writeable memory map backed by a file. |
245 | /// |
246 | /// # Errors |
247 | /// |
248 | /// This method returns an error when the underlying system call fails, which can happen for a |
249 | /// variety of reasons, such as when the file is not open with read and write permissions. |
250 | /// |
251 | /// # Example |
252 | /// |
253 | /// ``` |
254 | /// # extern crate memmap2; |
255 | /// # extern crate tempdir; |
256 | /// # |
257 | /// use std::fs::OpenOptions; |
258 | /// use std::path::PathBuf; |
259 | /// |
260 | /// use memmap2::MmapOptions; |
261 | /// # |
262 | /// # fn main() -> std::io::Result<()> { |
263 | /// # let tempdir = tempdir::TempDir::new("mmap" )?; |
264 | /// let path: PathBuf = /* path to file */ |
265 | /// # tempdir.path().join("map_mut" ); |
266 | /// let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?; |
267 | /// file.set_len(13)?; |
268 | /// |
269 | /// let mut mmap = unsafe { |
270 | /// MmapOptions::new().map_mut(&file)? |
271 | /// }; |
272 | /// |
273 | /// mmap.copy_from_slice(b"Hello, world!" ); |
274 | /// # Ok(()) |
275 | /// # } |
276 | /// ``` |
277 | pub unsafe fn map_mut(&self, file: &File) -> Result<MmapMut> { |
278 | MmapInner::map_mut(self.get_len(file)?, file, self.offset, self.populate) |
279 | .map(|inner| MmapMut { inner }) |
280 | } |
281 | |
282 | /// Creates a copy-on-write memory map backed by a file. |
283 | /// |
284 | /// Data written to the memory map will not be visible by other processes, |
285 | /// and will not be carried through to the underlying file. |
286 | /// |
287 | /// # Errors |
288 | /// |
289 | /// This method returns an error when the underlying system call fails, which can happen for a |
290 | /// variety of reasons, such as when the file is not open with writable permissions. |
291 | /// |
292 | /// # Example |
293 | /// |
294 | /// ``` |
295 | /// use memmap2::MmapOptions; |
296 | /// use std::fs::File; |
297 | /// use std::io::Write; |
298 | /// |
299 | /// # fn main() -> std::io::Result<()> { |
300 | /// let file = File::open("LICENSE-APACHE" )?; |
301 | /// let mut mmap = unsafe { MmapOptions::new().map_copy(&file)? }; |
302 | /// (&mut mmap[..]).write_all(b"Hello, world!" )?; |
303 | /// # Ok(()) |
304 | /// # } |
305 | /// ``` |
306 | pub unsafe fn map_copy(&self, file: &File) -> Result<MmapMut> { |
307 | MmapInner::map_copy(self.get_len(file)?, file, self.offset, self.populate) |
308 | .map(|inner| MmapMut { inner }) |
309 | } |
310 | |
311 | /// Creates a copy-on-write read-only memory map backed by a file. |
312 | /// |
313 | /// # Errors |
314 | /// |
315 | /// This method returns an error when the underlying system call fails, which can happen for a |
316 | /// variety of reasons, such as when the file is not open with read permissions. |
317 | /// |
318 | /// # Example |
319 | /// |
320 | /// ``` |
321 | /// use memmap2::MmapOptions; |
322 | /// use std::fs::File; |
323 | /// use std::io::Read; |
324 | /// |
325 | /// # fn main() -> std::io::Result<()> { |
326 | /// let mut file = File::open("README.md" )?; |
327 | /// |
328 | /// let mut contents = Vec::new(); |
329 | /// file.read_to_end(&mut contents)?; |
330 | /// |
331 | /// let mmap = unsafe { |
332 | /// MmapOptions::new().map_copy_read_only(&file)? |
333 | /// }; |
334 | /// |
335 | /// assert_eq!(&contents[..], &mmap[..]); |
336 | /// # Ok(()) |
337 | /// # } |
338 | /// ``` |
339 | pub unsafe fn map_copy_read_only(&self, file: &File) -> Result<Mmap> { |
340 | MmapInner::map_copy_read_only(self.get_len(file)?, file, self.offset, self.populate) |
341 | .map(|inner| Mmap { inner }) |
342 | } |
343 | |
344 | /// Creates an anonymous memory map. |
345 | /// |
346 | /// Note: the memory map length must be configured to be greater than 0 before creating an |
347 | /// anonymous memory map using `MmapOptions::len()`. |
348 | /// |
349 | /// # Errors |
350 | /// |
351 | /// This method returns an error when the underlying system call fails. |
352 | pub fn map_anon(&self) -> Result<MmapMut> { |
353 | MmapInner::map_anon(self.len.unwrap_or(0), self.stack).map(|inner| MmapMut { inner }) |
354 | } |
355 | |
356 | /// Creates a raw memory map. |
357 | /// |
358 | /// # Errors |
359 | /// |
360 | /// This method returns an error when the underlying system call fails, which can happen for a |
361 | /// variety of reasons, such as when the file is not open with read and write permissions. |
362 | pub fn map_raw(&self, file: &File) -> Result<MmapRaw> { |
363 | MmapInner::map_mut(self.get_len(file)?, file, self.offset, self.populate) |
364 | .map(|inner| MmapRaw { inner }) |
365 | } |
366 | } |
367 | |
368 | /// A handle to an immutable memory mapped buffer. |
369 | /// |
370 | /// A `Mmap` may be backed by a file, or it can be anonymous map, backed by volatile memory. Use |
371 | /// [`MmapOptions`] or [`map()`] to create a file-backed memory map. To create an immutable |
372 | /// anonymous memory map, first create a mutable anonymous memory map, and then make it immutable |
373 | /// with [`MmapMut::make_read_only()`]. |
374 | /// |
375 | /// A file backed `Mmap` is created by `&File` reference, and will remain valid even after the |
376 | /// `File` is dropped. In other words, the `Mmap` handle is completely independent of the `File` |
377 | /// used to create it. For consistency, on some platforms this is achieved by duplicating the |
378 | /// underlying file handle. The memory will be unmapped when the `Mmap` handle is dropped. |
379 | /// |
380 | /// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping |
381 | /// the mapped pages into physical memory) though the details of this are platform specific. |
382 | /// |
383 | /// `Mmap` is [`Sync`](std::marker::Sync) and [`Send`](std::marker::Send). |
384 | /// |
385 | /// ## Safety |
386 | /// |
387 | /// All file-backed memory map constructors are marked `unsafe` because of the potential for |
388 | /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or |
389 | /// out of process. Applications must consider the risk and take appropriate precautions when using |
390 | /// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked) |
391 | /// files exist but are platform specific and limited. |
392 | /// |
393 | /// ## Example |
394 | /// |
395 | /// ``` |
396 | /// use memmap2::MmapOptions; |
397 | /// use std::io::Write; |
398 | /// use std::fs::File; |
399 | /// |
400 | /// # fn main() -> std::io::Result<()> { |
401 | /// let file = File::open("README.md" )?; |
402 | /// let mmap = unsafe { MmapOptions::new().map(&file)? }; |
403 | /// assert_eq!(b"# memmap2" , &mmap[0..9]); |
404 | /// # Ok(()) |
405 | /// # } |
406 | /// ``` |
407 | /// |
408 | /// See [`MmapMut`] for the mutable version. |
409 | /// |
410 | /// [`map()`]: Mmap::map() |
411 | pub struct Mmap { |
412 | inner: MmapInner, |
413 | } |
414 | |
415 | impl Mmap { |
416 | /// Creates a read-only memory map backed by a file. |
417 | /// |
418 | /// This is equivalent to calling `MmapOptions::new().map(file)`. |
419 | /// |
420 | /// # Errors |
421 | /// |
422 | /// This method returns an error when the underlying system call fails, which can happen for a |
423 | /// variety of reasons, such as when the file is not open with read permissions. |
424 | /// |
425 | /// # Example |
426 | /// |
427 | /// ``` |
428 | /// use std::fs::File; |
429 | /// use std::io::Read; |
430 | /// |
431 | /// use memmap2::Mmap; |
432 | /// |
433 | /// # fn main() -> std::io::Result<()> { |
434 | /// let mut file = File::open("LICENSE-APACHE" )?; |
435 | /// |
436 | /// let mut contents = Vec::new(); |
437 | /// file.read_to_end(&mut contents)?; |
438 | /// |
439 | /// let mmap = unsafe { Mmap::map(&file)? }; |
440 | /// |
441 | /// assert_eq!(&contents[..], &mmap[..]); |
442 | /// # Ok(()) |
443 | /// # } |
444 | /// ``` |
445 | pub unsafe fn map(file: &File) -> Result<Mmap> { |
446 | MmapOptions::new().map(file) |
447 | } |
448 | |
449 | /// Transition the memory map to be writable. |
450 | /// |
451 | /// If the memory map is file-backed, the file must have been opened with write permissions. |
452 | /// |
453 | /// # Errors |
454 | /// |
455 | /// This method returns an error when the underlying system call fails, which can happen for a |
456 | /// variety of reasons, such as when the file is not open with writable permissions. |
457 | /// |
458 | /// # Example |
459 | /// |
460 | /// ``` |
461 | /// # extern crate memmap2; |
462 | /// # extern crate tempdir; |
463 | /// # |
464 | /// use memmap2::Mmap; |
465 | /// use std::ops::DerefMut; |
466 | /// use std::io::Write; |
467 | /// # use std::fs::OpenOptions; |
468 | /// |
469 | /// # fn main() -> std::io::Result<()> { |
470 | /// # let tempdir = tempdir::TempDir::new("mmap" )?; |
471 | /// let file = /* file opened with write permissions */ |
472 | /// # OpenOptions::new() |
473 | /// # .read(true) |
474 | /// # .write(true) |
475 | /// # .create(true) |
476 | /// # .open(tempdir.path() |
477 | /// # .join("make_mut" ))?; |
478 | /// # file.set_len(128)?; |
479 | /// let mmap = unsafe { Mmap::map(&file)? }; |
480 | /// // ... use the read-only memory map ... |
481 | /// let mut mut_mmap = mmap.make_mut()?; |
482 | /// mut_mmap.deref_mut().write_all(b"hello, world!" )?; |
483 | /// # Ok(()) |
484 | /// # } |
485 | /// ``` |
486 | pub fn make_mut(mut self) -> Result<MmapMut> { |
487 | self.inner.make_mut()?; |
488 | Ok(MmapMut { inner: self.inner }) |
489 | } |
490 | } |
491 | |
492 | impl Deref for Mmap { |
493 | type Target = [u8]; |
494 | |
495 | #[inline ] |
496 | fn deref(&self) -> &[u8] { |
497 | unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) } |
498 | } |
499 | } |
500 | |
501 | impl AsRef<[u8]> for Mmap { |
502 | #[inline ] |
503 | fn as_ref(&self) -> &[u8] { |
504 | self.deref() |
505 | } |
506 | } |
507 | |
508 | impl fmt::Debug for Mmap { |
509 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
510 | fmt&mut DebugStruct<'_, '_>.debug_struct("Mmap" ) |
511 | .field("ptr" , &self.as_ptr()) |
512 | .field(name:"len" , &self.len()) |
513 | .finish() |
514 | } |
515 | } |
516 | |
517 | /// A handle to a raw memory mapped buffer. |
518 | /// |
519 | /// This struct never hands out references to its interior, only raw pointers. |
520 | /// This can be helpful when creating shared memory maps between untrusted processes. |
521 | pub struct MmapRaw { |
522 | inner: MmapInner, |
523 | } |
524 | |
525 | impl MmapRaw { |
526 | /// Creates a writeable memory map backed by a file. |
527 | /// |
528 | /// This is equivalent to calling `MmapOptions::new().map_raw(file)`. |
529 | /// |
530 | /// # Errors |
531 | /// |
532 | /// This method returns an error when the underlying system call fails, which can happen for a |
533 | /// variety of reasons, such as when the file is not open with read and write permissions. |
534 | pub fn map_raw(file: &File) -> Result<MmapRaw> { |
535 | MmapOptions::new().map_raw(file) |
536 | } |
537 | |
538 | /// Returns a raw pointer to the memory mapped file. |
539 | /// |
540 | /// Before dereferencing this pointer, you have to make sure that the file has not been |
541 | /// truncated since the memory map was created. |
542 | /// Avoiding this will not introduce memory safety issues in Rust terms, |
543 | /// but will cause SIGBUS (or equivalent) signal. |
544 | #[inline ] |
545 | pub fn as_ptr(&self) -> *const u8 { |
546 | self.inner.ptr() |
547 | } |
548 | |
549 | /// Returns an unsafe mutable pointer to the memory mapped file. |
550 | /// |
551 | /// Before dereferencing this pointer, you have to make sure that the file has not been |
552 | /// truncated since the memory map was created. |
553 | /// Avoiding this will not introduce memory safety issues in Rust terms, |
554 | /// but will cause SIGBUS (or equivalent) signal. |
555 | #[inline ] |
556 | pub fn as_mut_ptr(&self) -> *mut u8 { |
557 | self.inner.ptr() as _ |
558 | } |
559 | |
560 | /// Returns the length in bytes of the memory map. |
561 | /// |
562 | /// Note that truncating the file can cause the length to change (and render this value unusable). |
563 | #[inline ] |
564 | pub fn len(&self) -> usize { |
565 | self.inner.len() |
566 | } |
567 | } |
568 | |
569 | impl fmt::Debug for MmapRaw { |
570 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
571 | fmt&mut DebugStruct<'_, '_>.debug_struct("MmapRaw" ) |
572 | .field("ptr" , &self.as_ptr()) |
573 | .field(name:"len" , &self.len()) |
574 | .finish() |
575 | } |
576 | } |
577 | |
578 | /// A handle to a mutable memory mapped buffer. |
579 | /// |
580 | /// A file-backed `MmapMut` buffer may be used to read from or write to a file. An anonymous |
581 | /// `MmapMut` buffer may be used any place that an in-memory byte buffer is needed. Use |
582 | /// [`MmapMut::map_mut()`] and [`MmapMut::map_anon()`] to create a mutable memory map of the |
583 | /// respective types, or [`MmapOptions::map_mut()`] and [`MmapOptions::map_anon()`] if non-default |
584 | /// options are required. |
585 | /// |
586 | /// A file backed `MmapMut` is created by `&File` reference, and will remain valid even after the |
587 | /// `File` is dropped. In other words, the `MmapMut` handle is completely independent of the `File` |
588 | /// used to create it. For consistency, on some platforms this is achieved by duplicating the |
589 | /// underlying file handle. The memory will be unmapped when the `MmapMut` handle is dropped. |
590 | /// |
591 | /// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping |
592 | /// the mapped pages into physical memory) though the details of this are platform specific. |
593 | /// |
594 | /// `Mmap` is [`Sync`](std::marker::Sync) and [`Send`](std::marker::Send). |
595 | /// |
596 | /// See [`Mmap`] for the immutable version. |
597 | /// |
598 | /// ## Safety |
599 | /// |
600 | /// All file-backed memory map constructors are marked `unsafe` because of the potential for |
601 | /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or |
602 | /// out of process. Applications must consider the risk and take appropriate precautions when using |
603 | /// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked) |
604 | /// files exist but are platform specific and limited. |
605 | pub struct MmapMut { |
606 | inner: MmapInner, |
607 | } |
608 | |
609 | impl MmapMut { |
610 | /// Creates a writeable memory map backed by a file. |
611 | /// |
612 | /// This is equivalent to calling `MmapOptions::new().map_mut(file)`. |
613 | /// |
614 | /// # Errors |
615 | /// |
616 | /// This method returns an error when the underlying system call fails, which can happen for a |
617 | /// variety of reasons, such as when the file is not open with read and write permissions. |
618 | /// |
619 | /// # Example |
620 | /// |
621 | /// ``` |
622 | /// # extern crate memmap2; |
623 | /// # extern crate tempdir; |
624 | /// # |
625 | /// use std::fs::OpenOptions; |
626 | /// use std::path::PathBuf; |
627 | /// |
628 | /// use memmap2::MmapMut; |
629 | /// # |
630 | /// # fn main() -> std::io::Result<()> { |
631 | /// # let tempdir = tempdir::TempDir::new("mmap" )?; |
632 | /// let path: PathBuf = /* path to file */ |
633 | /// # tempdir.path().join("map_mut" ); |
634 | /// let file = OpenOptions::new() |
635 | /// .read(true) |
636 | /// .write(true) |
637 | /// .create(true) |
638 | /// .open(&path)?; |
639 | /// file.set_len(13)?; |
640 | /// |
641 | /// let mut mmap = unsafe { MmapMut::map_mut(&file)? }; |
642 | /// |
643 | /// mmap.copy_from_slice(b"Hello, world!" ); |
644 | /// # Ok(()) |
645 | /// # } |
646 | /// ``` |
647 | pub unsafe fn map_mut(file: &File) -> Result<MmapMut> { |
648 | MmapOptions::new().map_mut(file) |
649 | } |
650 | |
651 | /// Creates an anonymous memory map. |
652 | /// |
653 | /// This is equivalent to calling `MmapOptions::new().len(length).map_anon()`. |
654 | /// |
655 | /// # Errors |
656 | /// |
657 | /// This method returns an error when the underlying system call fails. |
658 | pub fn map_anon(length: usize) -> Result<MmapMut> { |
659 | MmapOptions::new().len(length).map_anon() |
660 | } |
661 | |
662 | /// Flushes outstanding memory map modifications to disk. |
663 | /// |
664 | /// When this method returns with a non-error result, all outstanding changes to a file-backed |
665 | /// memory map are guaranteed to be durably stored. The file's metadata (including last |
666 | /// modification timestamp) may not be updated. |
667 | /// |
668 | /// # Example |
669 | /// |
670 | /// ``` |
671 | /// # extern crate memmap2; |
672 | /// # extern crate tempdir; |
673 | /// # |
674 | /// use std::fs::OpenOptions; |
675 | /// use std::io::Write; |
676 | /// use std::path::PathBuf; |
677 | /// |
678 | /// use memmap2::MmapMut; |
679 | /// |
680 | /// # fn main() -> std::io::Result<()> { |
681 | /// # let tempdir = tempdir::TempDir::new("mmap" )?; |
682 | /// let path: PathBuf = /* path to file */ |
683 | /// # tempdir.path().join("flush" ); |
684 | /// let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?; |
685 | /// file.set_len(128)?; |
686 | /// |
687 | /// let mut mmap = unsafe { MmapMut::map_mut(&file)? }; |
688 | /// |
689 | /// (&mut mmap[..]).write_all(b"Hello, world!" )?; |
690 | /// mmap.flush()?; |
691 | /// # Ok(()) |
692 | /// # } |
693 | /// ``` |
694 | pub fn flush(&self) -> Result<()> { |
695 | let len = self.len(); |
696 | self.inner.flush(0, len) |
697 | } |
698 | |
699 | /// Asynchronously flushes outstanding memory map modifications to disk. |
700 | /// |
701 | /// This method initiates flushing modified pages to durable storage, but it will not wait for |
702 | /// the operation to complete before returning. The file's metadata (including last |
703 | /// modification timestamp) may not be updated. |
704 | pub fn flush_async(&self) -> Result<()> { |
705 | let len = self.len(); |
706 | self.inner.flush_async(0, len) |
707 | } |
708 | |
709 | /// Flushes outstanding memory map modifications in the range to disk. |
710 | /// |
711 | /// The offset and length must be in the bounds of the memory map. |
712 | /// |
713 | /// When this method returns with a non-error result, all outstanding changes to a file-backed |
714 | /// memory in the range are guaranteed to be durable stored. The file's metadata (including |
715 | /// last modification timestamp) may not be updated. It is not guaranteed the only the changes |
716 | /// in the specified range are flushed; other outstanding changes to the memory map may be |
717 | /// flushed as well. |
718 | pub fn flush_range(&self, offset: usize, len: usize) -> Result<()> { |
719 | self.inner.flush(offset, len) |
720 | } |
721 | |
722 | /// Asynchronously flushes outstanding memory map modifications in the range to disk. |
723 | /// |
724 | /// The offset and length must be in the bounds of the memory map. |
725 | /// |
726 | /// This method initiates flushing modified pages to durable storage, but it will not wait for |
727 | /// the operation to complete before returning. The file's metadata (including last |
728 | /// modification timestamp) may not be updated. It is not guaranteed that the only changes |
729 | /// flushed are those in the specified range; other outstanding changes to the memory map may |
730 | /// be flushed as well. |
731 | pub fn flush_async_range(&self, offset: usize, len: usize) -> Result<()> { |
732 | self.inner.flush_async(offset, len) |
733 | } |
734 | |
735 | /// Returns an immutable version of this memory mapped buffer. |
736 | /// |
737 | /// If the memory map is file-backed, the file must have been opened with read permissions. |
738 | /// |
739 | /// # Errors |
740 | /// |
741 | /// This method returns an error when the underlying system call fails, which can happen for a |
742 | /// variety of reasons, such as when the file has not been opened with read permissions. |
743 | /// |
744 | /// # Example |
745 | /// |
746 | /// ``` |
747 | /// # extern crate memmap2; |
748 | /// # |
749 | /// use std::io::Write; |
750 | /// use std::path::PathBuf; |
751 | /// |
752 | /// use memmap2::{Mmap, MmapMut}; |
753 | /// |
754 | /// # fn main() -> std::io::Result<()> { |
755 | /// let mut mmap = MmapMut::map_anon(128)?; |
756 | /// |
757 | /// (&mut mmap[..]).write(b"Hello, world!" )?; |
758 | /// |
759 | /// let mmap: Mmap = mmap.make_read_only()?; |
760 | /// # Ok(()) |
761 | /// # } |
762 | /// ``` |
763 | pub fn make_read_only(mut self) -> Result<Mmap> { |
764 | self.inner.make_read_only()?; |
765 | Ok(Mmap { inner: self.inner }) |
766 | } |
767 | |
768 | /// Transition the memory map to be readable and executable. |
769 | /// |
770 | /// If the memory map is file-backed, the file must have been opened with execute permissions. |
771 | /// |
772 | /// # Errors |
773 | /// |
774 | /// This method returns an error when the underlying system call fails, which can happen for a |
775 | /// variety of reasons, such as when the file has not been opened with execute permissions. |
776 | pub fn make_exec(mut self) -> Result<Mmap> { |
777 | self.inner.make_exec()?; |
778 | Ok(Mmap { inner: self.inner }) |
779 | } |
780 | } |
781 | |
782 | impl Deref for MmapMut { |
783 | type Target = [u8]; |
784 | |
785 | #[inline ] |
786 | fn deref(&self) -> &[u8] { |
787 | unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) } |
788 | } |
789 | } |
790 | |
791 | impl DerefMut for MmapMut { |
792 | #[inline ] |
793 | fn deref_mut(&mut self) -> &mut [u8] { |
794 | unsafe { slice::from_raw_parts_mut(self.inner.mut_ptr(), self.inner.len()) } |
795 | } |
796 | } |
797 | |
798 | impl AsRef<[u8]> for MmapMut { |
799 | #[inline ] |
800 | fn as_ref(&self) -> &[u8] { |
801 | self.deref() |
802 | } |
803 | } |
804 | |
805 | impl AsMut<[u8]> for MmapMut { |
806 | #[inline ] |
807 | fn as_mut(&mut self) -> &mut [u8] { |
808 | self.deref_mut() |
809 | } |
810 | } |
811 | |
812 | impl fmt::Debug for MmapMut { |
813 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
814 | fmt&mut DebugStruct<'_, '_>.debug_struct("MmapMut" ) |
815 | .field("ptr" , &self.as_ptr()) |
816 | .field(name:"len" , &self.len()) |
817 | .finish() |
818 | } |
819 | } |
820 | |
821 | #[cfg (test)] |
822 | mod test { |
823 | extern crate tempdir; |
824 | |
825 | use std::fs::OpenOptions; |
826 | use std::io::{Read, Write}; |
827 | #[cfg (windows)] |
828 | use std::os::windows::fs::OpenOptionsExt; |
829 | |
830 | #[cfg (windows)] |
831 | const GENERIC_ALL: u32 = 0x10000000; |
832 | |
833 | use super::{Mmap, MmapMut, MmapOptions}; |
834 | |
835 | #[test ] |
836 | fn map_file() { |
837 | let expected_len = 128; |
838 | let tempdir = tempdir::TempDir::new("mmap" ).unwrap(); |
839 | let path = tempdir.path().join("mmap" ); |
840 | |
841 | let file = OpenOptions::new() |
842 | .read(true) |
843 | .write(true) |
844 | .create(true) |
845 | .open(&path) |
846 | .unwrap(); |
847 | |
848 | file.set_len(expected_len as u64).unwrap(); |
849 | |
850 | let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; |
851 | let len = mmap.len(); |
852 | assert_eq!(expected_len, len); |
853 | |
854 | let zeros = vec![0; len]; |
855 | let incr: Vec<u8> = (0..len as u8).collect(); |
856 | |
857 | // check that the mmap is empty |
858 | assert_eq!(&zeros[..], &mmap[..]); |
859 | |
860 | // write values into the mmap |
861 | (&mut mmap[..]).write_all(&incr[..]).unwrap(); |
862 | |
863 | // read values back |
864 | assert_eq!(&incr[..], &mmap[..]); |
865 | } |
866 | |
867 | /// Checks that a 0-length file will not be mapped. |
868 | #[test ] |
869 | fn map_empty_file() { |
870 | let tempdir = tempdir::TempDir::new("mmap" ).unwrap(); |
871 | let path = tempdir.path().join("mmap" ); |
872 | |
873 | let file = OpenOptions::new() |
874 | .read(true) |
875 | .write(true) |
876 | .create(true) |
877 | .open(&path) |
878 | .unwrap(); |
879 | let mmap = unsafe { Mmap::map(&file) }; |
880 | assert!(mmap.is_err()); |
881 | } |
882 | |
883 | #[test ] |
884 | fn map_anon() { |
885 | let expected_len = 128; |
886 | let mut mmap = MmapMut::map_anon(expected_len).unwrap(); |
887 | let len = mmap.len(); |
888 | assert_eq!(expected_len, len); |
889 | |
890 | let zeros = vec![0; len]; |
891 | let incr: Vec<u8> = (0..len as u8).collect(); |
892 | |
893 | // check that the mmap is empty |
894 | assert_eq!(&zeros[..], &mmap[..]); |
895 | |
896 | // write values into the mmap |
897 | (&mut mmap[..]).write_all(&incr[..]).unwrap(); |
898 | |
899 | // read values back |
900 | assert_eq!(&incr[..], &mmap[..]); |
901 | } |
902 | |
903 | #[test ] |
904 | fn map_anon_zero_len() { |
905 | assert!(MmapOptions::new().map_anon().is_err()) |
906 | } |
907 | |
908 | #[test ] |
909 | fn file_write() { |
910 | let tempdir = tempdir::TempDir::new("mmap" ).unwrap(); |
911 | let path = tempdir.path().join("mmap" ); |
912 | |
913 | let mut file = OpenOptions::new() |
914 | .read(true) |
915 | .write(true) |
916 | .create(true) |
917 | .open(&path) |
918 | .unwrap(); |
919 | file.set_len(128).unwrap(); |
920 | |
921 | let write = b"abc123" ; |
922 | let mut read = [0u8; 6]; |
923 | |
924 | let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; |
925 | (&mut mmap[..]).write_all(write).unwrap(); |
926 | mmap.flush().unwrap(); |
927 | |
928 | file.read_exact(&mut read).unwrap(); |
929 | assert_eq!(write, &read); |
930 | } |
931 | |
932 | #[test ] |
933 | fn flush_range() { |
934 | let tempdir = tempdir::TempDir::new("mmap" ).unwrap(); |
935 | let path = tempdir.path().join("mmap" ); |
936 | |
937 | let file = OpenOptions::new() |
938 | .read(true) |
939 | .write(true) |
940 | .create(true) |
941 | .open(&path) |
942 | .unwrap(); |
943 | file.set_len(128).unwrap(); |
944 | let write = b"abc123" ; |
945 | |
946 | let mut mmap = unsafe { |
947 | MmapOptions::new() |
948 | .offset(2) |
949 | .len(write.len()) |
950 | .map_mut(&file) |
951 | .unwrap() |
952 | }; |
953 | (&mut mmap[..]).write_all(write).unwrap(); |
954 | mmap.flush_async_range(0, write.len()).unwrap(); |
955 | mmap.flush_range(0, write.len()).unwrap(); |
956 | } |
957 | |
958 | #[test ] |
959 | fn map_copy() { |
960 | let tempdir = tempdir::TempDir::new("mmap" ).unwrap(); |
961 | let path = tempdir.path().join("mmap" ); |
962 | |
963 | let mut file = OpenOptions::new() |
964 | .read(true) |
965 | .write(true) |
966 | .create(true) |
967 | .open(&path) |
968 | .unwrap(); |
969 | file.set_len(128).unwrap(); |
970 | |
971 | let nulls = b" \0\0\0\0\0\0" ; |
972 | let write = b"abc123" ; |
973 | let mut read = [0u8; 6]; |
974 | |
975 | let mut mmap = unsafe { MmapOptions::new().map_copy(&file).unwrap() }; |
976 | |
977 | (&mut mmap[..]).write_all(write).unwrap(); |
978 | mmap.flush().unwrap(); |
979 | |
980 | // The mmap contains the write |
981 | (&mmap[..]).read_exact(&mut read).unwrap(); |
982 | assert_eq!(write, &read); |
983 | |
984 | // The file does not contain the write |
985 | file.read_exact(&mut read).unwrap(); |
986 | assert_eq!(nulls, &read); |
987 | |
988 | // another mmap does not contain the write |
989 | let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; |
990 | (&mmap2[..]).read_exact(&mut read).unwrap(); |
991 | assert_eq!(nulls, &read); |
992 | } |
993 | |
994 | #[test ] |
995 | fn map_copy_read_only() { |
996 | let tempdir = tempdir::TempDir::new("mmap" ).unwrap(); |
997 | let path = tempdir.path().join("mmap" ); |
998 | |
999 | let file = OpenOptions::new() |
1000 | .read(true) |
1001 | .write(true) |
1002 | .create(true) |
1003 | .open(&path) |
1004 | .unwrap(); |
1005 | file.set_len(128).unwrap(); |
1006 | |
1007 | let nulls = b" \0\0\0\0\0\0" ; |
1008 | let mut read = [0u8; 6]; |
1009 | |
1010 | let mmap = unsafe { MmapOptions::new().map_copy_read_only(&file).unwrap() }; |
1011 | (&mmap[..]).read_exact(&mut read).unwrap(); |
1012 | assert_eq!(nulls, &read); |
1013 | |
1014 | let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; |
1015 | (&mmap2[..]).read_exact(&mut read).unwrap(); |
1016 | assert_eq!(nulls, &read); |
1017 | } |
1018 | |
1019 | #[test ] |
1020 | fn map_offset() { |
1021 | let tempdir = tempdir::TempDir::new("mmap" ).unwrap(); |
1022 | let path = tempdir.path().join("mmap" ); |
1023 | |
1024 | let file = OpenOptions::new() |
1025 | .read(true) |
1026 | .write(true) |
1027 | .create(true) |
1028 | .open(&path) |
1029 | .unwrap(); |
1030 | |
1031 | let offset = u32::max_value() as u64 + 2; |
1032 | let len = 5432; |
1033 | file.set_len(offset + len as u64).unwrap(); |
1034 | |
1035 | // Check inferred length mmap. |
1036 | let mmap = unsafe { MmapOptions::new().offset(offset).map_mut(&file).unwrap() }; |
1037 | assert_eq!(len, mmap.len()); |
1038 | |
1039 | // Check explicit length mmap. |
1040 | let mut mmap = unsafe { |
1041 | MmapOptions::new() |
1042 | .offset(offset) |
1043 | .len(len) |
1044 | .map_mut(&file) |
1045 | .unwrap() |
1046 | }; |
1047 | assert_eq!(len, mmap.len()); |
1048 | |
1049 | let zeros = vec![0; len]; |
1050 | let incr: Vec<_> = (0..len).map(|i| i as u8).collect(); |
1051 | |
1052 | // check that the mmap is empty |
1053 | assert_eq!(&zeros[..], &mmap[..]); |
1054 | |
1055 | // write values into the mmap |
1056 | (&mut mmap[..]).write_all(&incr[..]).unwrap(); |
1057 | |
1058 | // read values back |
1059 | assert_eq!(&incr[..], &mmap[..]); |
1060 | } |
1061 | |
1062 | #[test ] |
1063 | fn index() { |
1064 | let mut mmap = MmapMut::map_anon(128).unwrap(); |
1065 | mmap[0] = 42; |
1066 | assert_eq!(42, mmap[0]); |
1067 | } |
1068 | |
1069 | #[test ] |
1070 | fn sync_send() { |
1071 | let mmap = MmapMut::map_anon(129).unwrap(); |
1072 | |
1073 | fn is_sync_send<T>(_val: T) |
1074 | where |
1075 | T: Sync + Send, |
1076 | { |
1077 | } |
1078 | |
1079 | is_sync_send(mmap); |
1080 | } |
1081 | |
1082 | #[cfg (any(target_arch = "x86" , target_arch = "x86_64" ))] |
1083 | fn jit_x86(mut mmap: MmapMut) { |
1084 | use std::mem; |
1085 | mmap[0] = 0xB8; // mov eax, 0xAB |
1086 | mmap[1] = 0xAB; |
1087 | mmap[2] = 0x00; |
1088 | mmap[3] = 0x00; |
1089 | mmap[4] = 0x00; |
1090 | mmap[5] = 0xC3; // ret |
1091 | |
1092 | let mmap = mmap.make_exec().expect("make_exec" ); |
1093 | |
1094 | let jitfn: extern "C" fn() -> u8 = unsafe { mem::transmute(mmap.as_ptr()) }; |
1095 | assert_eq!(jitfn(), 0xab); |
1096 | } |
1097 | |
1098 | #[test ] |
1099 | #[cfg (any(target_arch = "x86" , target_arch = "x86_64" ))] |
1100 | fn jit_x86_anon() { |
1101 | jit_x86(MmapMut::map_anon(4096).unwrap()); |
1102 | } |
1103 | |
1104 | #[test ] |
1105 | #[cfg (any(target_arch = "x86" , target_arch = "x86_64" ))] |
1106 | fn jit_x86_file() { |
1107 | let tempdir = tempdir::TempDir::new("mmap" ).unwrap(); |
1108 | let mut options = OpenOptions::new(); |
1109 | #[cfg (windows)] |
1110 | options.access_mode(GENERIC_ALL); |
1111 | |
1112 | let file = options |
1113 | .read(true) |
1114 | .write(true) |
1115 | .create(true) |
1116 | .open(&tempdir.path().join("jit_x86" )) |
1117 | .expect("open" ); |
1118 | |
1119 | file.set_len(4096).expect("set_len" ); |
1120 | jit_x86(unsafe { MmapMut::map_mut(&file).expect("map_mut" ) }); |
1121 | } |
1122 | |
1123 | #[test ] |
1124 | fn mprotect_file() { |
1125 | let tempdir = tempdir::TempDir::new("mmap" ).unwrap(); |
1126 | let path = tempdir.path().join("mmap" ); |
1127 | |
1128 | let mut options = OpenOptions::new(); |
1129 | #[cfg (windows)] |
1130 | options.access_mode(GENERIC_ALL); |
1131 | |
1132 | let mut file = options |
1133 | .read(true) |
1134 | .write(true) |
1135 | .create(true) |
1136 | .open(&path) |
1137 | .expect("open" ); |
1138 | file.set_len(256_u64).expect("set_len" ); |
1139 | |
1140 | let mmap = unsafe { MmapMut::map_mut(&file).expect("map_mut" ) }; |
1141 | |
1142 | let mmap = mmap.make_read_only().expect("make_read_only" ); |
1143 | let mut mmap = mmap.make_mut().expect("make_mut" ); |
1144 | |
1145 | let write = b"abc123" ; |
1146 | let mut read = [0u8; 6]; |
1147 | |
1148 | (&mut mmap[..]).write_all(write).unwrap(); |
1149 | mmap.flush().unwrap(); |
1150 | |
1151 | // The mmap contains the write |
1152 | (&mmap[..]).read_exact(&mut read).unwrap(); |
1153 | assert_eq!(write, &read); |
1154 | |
1155 | // The file should contain the write |
1156 | file.read_exact(&mut read).unwrap(); |
1157 | assert_eq!(write, &read); |
1158 | |
1159 | // another mmap should contain the write |
1160 | let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; |
1161 | (&mmap2[..]).read_exact(&mut read).unwrap(); |
1162 | assert_eq!(write, &read); |
1163 | |
1164 | let mmap = mmap.make_exec().expect("make_exec" ); |
1165 | |
1166 | drop(mmap); |
1167 | } |
1168 | |
1169 | #[test ] |
1170 | fn mprotect_copy() { |
1171 | let tempdir = tempdir::TempDir::new("mmap" ).unwrap(); |
1172 | let path = tempdir.path().join("mmap" ); |
1173 | |
1174 | let mut options = OpenOptions::new(); |
1175 | #[cfg (windows)] |
1176 | options.access_mode(GENERIC_ALL); |
1177 | |
1178 | let mut file = options |
1179 | .read(true) |
1180 | .write(true) |
1181 | .create(true) |
1182 | .open(&path) |
1183 | .expect("open" ); |
1184 | file.set_len(256_u64).expect("set_len" ); |
1185 | |
1186 | let mmap = unsafe { MmapOptions::new().map_copy(&file).expect("map_mut" ) }; |
1187 | |
1188 | let mmap = mmap.make_read_only().expect("make_read_only" ); |
1189 | let mut mmap = mmap.make_mut().expect("make_mut" ); |
1190 | |
1191 | let nulls = b" \0\0\0\0\0\0" ; |
1192 | let write = b"abc123" ; |
1193 | let mut read = [0u8; 6]; |
1194 | |
1195 | (&mut mmap[..]).write_all(write).unwrap(); |
1196 | mmap.flush().unwrap(); |
1197 | |
1198 | // The mmap contains the write |
1199 | (&mmap[..]).read_exact(&mut read).unwrap(); |
1200 | assert_eq!(write, &read); |
1201 | |
1202 | // The file does not contain the write |
1203 | file.read_exact(&mut read).unwrap(); |
1204 | assert_eq!(nulls, &read); |
1205 | |
1206 | // another mmap does not contain the write |
1207 | let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; |
1208 | (&mmap2[..]).read_exact(&mut read).unwrap(); |
1209 | assert_eq!(nulls, &read); |
1210 | |
1211 | let mmap = mmap.make_exec().expect("make_exec" ); |
1212 | |
1213 | drop(mmap); |
1214 | } |
1215 | |
1216 | #[test ] |
1217 | fn mprotect_anon() { |
1218 | let mmap = MmapMut::map_anon(256).expect("map_mut" ); |
1219 | |
1220 | let mmap = mmap.make_read_only().expect("make_read_only" ); |
1221 | let mmap = mmap.make_mut().expect("make_mut" ); |
1222 | let mmap = mmap.make_exec().expect("make_exec" ); |
1223 | drop(mmap); |
1224 | } |
1225 | |
1226 | #[test ] |
1227 | fn raw() { |
1228 | let tempdir = tempdir::TempDir::new("mmap" ).unwrap(); |
1229 | let path = tempdir.path().join("mmapraw" ); |
1230 | |
1231 | let mut options = OpenOptions::new(); |
1232 | let mut file = options |
1233 | .read(true) |
1234 | .write(true) |
1235 | .create(true) |
1236 | .open(&path) |
1237 | .expect("open" ); |
1238 | file.write_all(b"abc123" ).unwrap(); |
1239 | let mmap = MmapOptions::new().map_raw(&file).unwrap(); |
1240 | assert_eq!(mmap.len(), 6); |
1241 | assert!(!mmap.as_ptr().is_null()); |
1242 | assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a' ); |
1243 | } |
1244 | } |
1245 | |