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)]
6mod windows;
7#[cfg(windows)]
8use windows::MmapInner;
9
10#[cfg(unix)]
11mod unix;
12#[cfg(unix)]
13use unix::MmapInner;
14
15#[cfg(not(any(unix, windows)))]
16mod stub;
17#[cfg(not(any(unix, windows)))]
18use crate::stub::MmapInner;
19
20use std::fmt;
21use std::fs::File;
22use std::io::{Error, ErrorKind, Result};
23use std::ops::{Deref, DerefMut};
24use std::slice;
25use 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)]
48pub struct MmapOptions {
49 offset: u64,
50 len: Option<usize>,
51 stack: bool,
52 populate: bool,
53}
54
55impl 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()
411pub struct Mmap {
412 inner: MmapInner,
413}
414
415impl 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
492impl 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
501impl AsRef<[u8]> for Mmap {
502 #[inline]
503 fn as_ref(&self) -> &[u8] {
504 self.deref()
505 }
506}
507
508impl 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.
521pub struct MmapRaw {
522 inner: MmapInner,
523}
524
525impl 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
569impl 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.
605pub struct MmapMut {
606 inner: MmapInner,
607}
608
609impl 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
782impl 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
791impl 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
798impl AsRef<[u8]> for MmapMut {
799 #[inline]
800 fn as_ref(&self) -> &[u8] {
801 self.deref()
802 }
803}
804
805impl AsMut<[u8]> for MmapMut {
806 #[inline]
807 fn as_mut(&mut self) -> &mut [u8] {
808 self.deref_mut()
809 }
810}
811
812impl 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)]
822mod 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