memmap2/lib.rs
1#![deny(clippy::all, clippy::pedantic)]
2#![deny(unsafe_op_in_unsafe_fn)]
3#![allow(
4 // pedantic exceptions
5 clippy::cast_possible_truncation,
6 clippy::cast_possible_wrap,
7 clippy::cast_sign_loss,
8 clippy::doc_markdown,
9 clippy::explicit_deref_methods,
10 clippy::missing_errors_doc,
11 clippy::module_name_repetitions,
12 clippy::must_use_candidate,
13 clippy::needless_pass_by_value,
14 clippy::return_self_not_must_use,
15 clippy::unreadable_literal,
16 clippy::upper_case_acronyms,
17)]
18
19//! A cross-platform Rust API for memory mapped buffers.
20//!
21//! The core functionality is provided by either [`Mmap`] or [`MmapMut`],
22//! which correspond to mapping a [`File`] to a [`&[u8]`](https://doc.rust-lang.org/std/primitive.slice.html)
23//! or [`&mut [u8]`](https://doc.rust-lang.org/std/primitive.slice.html)
24//! respectively. Both function by dereferencing to a slice, allowing the
25//! [`Mmap`]/[`MmapMut`] to be used in the same way you would the equivalent slice
26//! types.
27//!
28//! [`File`]: std::fs::File
29//!
30//! # Examples
31//!
32//! For simple cases [`Mmap`] can be used directly:
33//!
34//! ```
35//! use std::fs::File;
36//! use std::io::Read;
37//!
38//! use memmap2::Mmap;
39//!
40//! # fn main() -> std::io::Result<()> {
41//! let mut file = File::open("LICENSE-APACHE")?;
42//!
43//! let mut contents = Vec::new();
44//! file.read_to_end(&mut contents)?;
45//!
46//! let mmap = unsafe { Mmap::map(&file)? };
47//!
48//! assert_eq!(&contents[..], &mmap[..]);
49//! # Ok(())
50//! # }
51//! ```
52//!
53//! However for cases which require configuration of the mapping, then
54//! you can use [`MmapOptions`] in order to further configure a mapping
55//! before you create it.
56
57#![allow(clippy::len_without_is_empty, clippy::missing_safety_doc)]
58
59#[cfg_attr(unix, path = "unix.rs")]
60#[cfg_attr(windows, path = "windows.rs")]
61#[cfg_attr(not(any(unix, windows)), path = "stub.rs")]
62mod os;
63use crate::os::{file_len, MmapInner};
64
65#[cfg(unix)]
66mod advice;
67#[cfg(unix)]
68pub use crate::advice::{Advice, UncheckedAdvice};
69
70use std::fmt;
71#[cfg(not(any(unix, windows)))]
72use std::fs::File;
73use std::io::{Error, ErrorKind};
74use std::ops::{Deref, DerefMut};
75#[cfg(unix)]
76use std::os::unix::io::{AsRawFd, RawFd};
77#[cfg(windows)]
78use std::os::windows::io::{AsRawHandle, RawHandle};
79use std::slice;
80
81#[cfg(not(any(unix, windows)))]
82pub struct MmapRawDescriptor<'a>(&'a File);
83
84#[cfg(unix)]
85pub struct MmapRawDescriptor(RawFd);
86
87#[cfg(windows)]
88pub struct MmapRawDescriptor(RawHandle);
89
90pub trait MmapAsRawDesc {
91 fn as_raw_desc(&self) -> MmapRawDescriptor;
92}
93
94#[cfg(not(any(unix, windows)))]
95impl MmapAsRawDesc for &File {
96 fn as_raw_desc(&self) -> MmapRawDescriptor {
97 MmapRawDescriptor(self)
98 }
99}
100
101#[cfg(unix)]
102impl MmapAsRawDesc for RawFd {
103 fn as_raw_desc(&self) -> MmapRawDescriptor {
104 MmapRawDescriptor(*self)
105 }
106}
107
108#[cfg(unix)]
109impl<T> MmapAsRawDesc for &T
110where
111 T: AsRawFd,
112{
113 fn as_raw_desc(&self) -> MmapRawDescriptor {
114 MmapRawDescriptor(self.as_raw_fd())
115 }
116}
117
118#[cfg(windows)]
119impl MmapAsRawDesc for RawHandle {
120 fn as_raw_desc(&self) -> MmapRawDescriptor {
121 MmapRawDescriptor(*self)
122 }
123}
124
125#[cfg(windows)]
126impl<T> MmapAsRawDesc for &T
127where
128 T: AsRawHandle,
129{
130 fn as_raw_desc(&self) -> MmapRawDescriptor {
131 MmapRawDescriptor(self.as_raw_handle())
132 }
133}
134
135/// Error returned by [`MmapOptions::map_if_safe()`].
136///
137/// Allows you to distinguish between three failure modes:
138///
139/// * Safe mapping is not supported on this platform.
140/// * Trying to map an unsafe file descriptor.
141/// * The map attempt itself failed.
142///
143/// The error is convertible to [`std::io::Error`].
144pub struct MapIfSafeError {
145 inner: MapIfSafeErrorInner,
146}
147
148#[derive(Debug)]
149#[allow(dead_code)] // Not all variants are constructed on all platforms.
150enum MapIfSafeErrorInner {
151 NotSupported,
152 NotSafe(std::io::Error),
153 MapFailed(std::io::Error),
154}
155
156impl MapIfSafeError {
157 #[allow(dead_code)] // Not all variants are constructed on all platforms.
158 fn new_not_supported() -> Self {
159 let inner = MapIfSafeErrorInner::NotSupported;
160 Self { inner }
161 }
162
163 #[allow(dead_code)] // Not all variants are constructed on all platforms.
164 fn new_not_safe(reason: std::io::Error) -> Self {
165 let inner = MapIfSafeErrorInner::NotSafe(reason);
166 Self { inner }
167 }
168
169 #[allow(dead_code)] // Not all variants are constructed on all platforms.
170 fn new_map_failed(reason: std::io::Error) -> Self {
171 let inner = MapIfSafeErrorInner::MapFailed(reason);
172 Self { inner }
173 }
174
175 /// Indicates that safe mapping is not supported at all on this platform.
176 pub fn not_supported(&self) -> bool {
177 matches!(self.inner, MapIfSafeErrorInner::NotSupported)
178 }
179
180 /// Indicates if the map was refused because mapping the file descriptor is not safe.
181 pub fn not_safe(&self) -> bool {
182 matches!(self.inner, MapIfSafeErrorInner::NotSafe(_))
183 }
184
185 /// Indicates if the file descriptor to be mapped was considered safe, but the mapping itself failed.
186 pub fn map_failed(&self) -> bool {
187 matches!(self.inner, MapIfSafeErrorInner::MapFailed(_))
188 }
189}
190
191impl std::error::Error for MapIfSafeError {}
192
193impl fmt::Display for MapIfSafeError {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 #[allow(clippy::match_same_arms)]
196 match &self.inner {
197 MapIfSafeErrorInner::NotSupported => {
198 fmt::Display::fmt(&Error::from(ErrorKind::Unsupported), f)
199 }
200 MapIfSafeErrorInner::NotSafe(e) => fmt::Display::fmt(e, f),
201 MapIfSafeErrorInner::MapFailed(e) => fmt::Display::fmt(e, f),
202 }
203 }
204}
205
206impl fmt::Debug for MapIfSafeError {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 fmt::Debug::fmt(&self.inner, f)
209 }
210}
211
212impl From<MapIfSafeError> for std::io::Error {
213 fn from(value: MapIfSafeError) -> Self {
214 #[allow(clippy::match_same_arms)]
215 match value.inner {
216 MapIfSafeErrorInner::NotSupported => std::io::ErrorKind::Unsupported.into(),
217 MapIfSafeErrorInner::NotSafe(e) => e,
218 MapIfSafeErrorInner::MapFailed(e) => e,
219 }
220 }
221}
222
223/// A memory map builder, providing advanced options and flags for specifying memory map behavior.
224///
225/// `MmapOptions` can be used to create an anonymous memory map using [`map_anon()`], or a
226/// file-backed memory map using one of [`map()`], [`map_mut()`], [`map_exec()`],
227/// [`map_copy()`], or [`map_copy_read_only()`].
228///
229/// ## Safety
230///
231/// All file-backed memory map constructors are marked `unsafe` because of the potential for
232/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
233/// out of process. Applications must consider the risk and take appropriate precautions when
234/// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g.
235/// unlinked) files exist but are platform specific and limited.
236///
237/// [`map_anon()`]: MmapOptions::map_anon()
238/// [`map()`]: MmapOptions::map()
239/// [`map_mut()`]: MmapOptions::map_mut()
240/// [`map_exec()`]: MmapOptions::map_exec()
241/// [`map_copy()`]: MmapOptions::map_copy()
242/// [`map_copy_read_only()`]: MmapOptions::map_copy_read_only()
243#[derive(Clone, Debug, Default)]
244#[allow(clippy::struct_excessive_bools)]
245pub struct MmapOptions {
246 offset: u64,
247 len: Option<usize>,
248 huge: Option<u8>,
249 stack: bool,
250 populate: bool,
251 no_reserve_swap: bool,
252 no_probe_handle: bool,
253}
254
255impl MmapOptions {
256 /// Creates a new set of options for configuring and creating a memory map.
257 ///
258 /// # Example
259 ///
260 /// ```
261 /// use memmap2::{MmapMut, MmapOptions};
262 /// # use std::io::Result;
263 ///
264 /// # fn main() -> Result<()> {
265 /// // Create a new memory map builder.
266 /// let mut mmap_options = MmapOptions::new();
267 ///
268 /// // Configure the memory map builder using option setters, then create
269 /// // a memory map using one of `mmap_options.map_anon`, `mmap_options.map`,
270 /// // `mmap_options.map_mut`, `mmap_options.map_exec`, or `mmap_options.map_copy`:
271 /// let mut mmap: MmapMut = mmap_options.len(36).map_anon()?;
272 ///
273 /// // Use the memory map:
274 /// mmap.copy_from_slice(b"...data to copy to the memory map...");
275 /// # Ok(())
276 /// # }
277 /// ```
278 pub fn new() -> MmapOptions {
279 MmapOptions::default()
280 }
281
282 /// Configures the memory map to start at byte `offset` from the beginning of the file.
283 ///
284 /// This option has no effect on anonymous memory maps.
285 ///
286 /// By default, the offset is 0.
287 ///
288 /// # Example
289 ///
290 /// ```
291 /// use memmap2::MmapOptions;
292 /// use std::fs::File;
293 ///
294 /// # fn main() -> std::io::Result<()> {
295 /// let mmap = unsafe {
296 /// MmapOptions::new()
297 /// .offset(30)
298 /// .map(&File::open("LICENSE-APACHE")?)?
299 /// };
300 /// assert_eq!(&b"Apache License"[..],
301 /// &mmap[..14]);
302 /// # Ok(())
303 /// # }
304 /// ```
305 pub fn offset(&mut self, offset: u64) -> &mut Self {
306 self.offset = offset;
307 self
308 }
309
310 /// Configures the created memory mapped buffer to be `len` bytes long.
311 ///
312 /// This option is mandatory for anonymous memory maps.
313 ///
314 /// For file-backed memory maps, the length will default to the file length.
315 ///
316 /// # Example
317 ///
318 /// ```
319 /// use memmap2::MmapOptions;
320 /// use std::fs::File;
321 ///
322 /// # fn main() -> std::io::Result<()> {
323 /// let mmap = unsafe {
324 /// MmapOptions::new()
325 /// .len(9)
326 /// .map(&File::open("README.md")?)?
327 /// };
328 /// assert_eq!(&b"# memmap2"[..], &mmap[..]);
329 /// # Ok(())
330 /// # }
331 /// ```
332 pub fn len(&mut self, len: usize) -> &mut Self {
333 self.len = Some(len);
334 self
335 }
336
337 fn validate_len(len: u64) -> std::io::Result<usize> {
338 // Rust's slice cannot be larger than isize::MAX.
339 // See https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html
340 //
341 // This is not a problem on 64-bit targets, but on 32-bit one
342 // having a file or an anonymous mapping larger than 2GB is quite normal
343 // and we have to prevent it.
344 if isize::try_from(len).is_err() {
345 return Err(Error::new(
346 ErrorKind::InvalidData,
347 "memory map length overflows isize",
348 ));
349 }
350 // If an unsigned number (u64) fits in isize, then it fits in usize.
351 Ok(len as usize)
352 }
353
354 /// Returns the configured length, or the length of the provided file.
355 fn get_len<T: MmapAsRawDesc>(&self, file: &T) -> std::io::Result<usize> {
356 let len = if let Some(len) = self.len {
357 len as u64
358 } else {
359 let desc = file.as_raw_desc();
360 let file_len = file_len(desc.0)?;
361
362 if file_len < self.offset {
363 return Err(Error::new(
364 ErrorKind::InvalidData,
365 "memory map offset is larger than length",
366 ));
367 }
368
369 file_len - self.offset
370 };
371 Self::validate_len(len)
372 }
373
374 /// Configures the anonymous memory map to be suitable for a process or thread stack.
375 ///
376 /// This option corresponds to the `MAP_STACK` flag on Linux. It has no effect on Windows.
377 ///
378 /// This option has no effect on file-backed memory maps.
379 ///
380 /// # Example
381 ///
382 /// ```
383 /// use memmap2::MmapOptions;
384 ///
385 /// # fn main() -> std::io::Result<()> {
386 /// let stack = MmapOptions::new().stack().len(4096).map_anon();
387 /// # Ok(())
388 /// # }
389 /// ```
390 pub fn stack(&mut self) -> &mut Self {
391 self.stack = true;
392 self
393 }
394
395 /// Configures the anonymous memory map to be allocated using huge pages.
396 ///
397 /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows.
398 ///
399 /// The size of the requested page can be specified in page bits. If not provided, the system
400 /// default is requested. The requested length should be a multiple of this, or the mapping
401 /// will fail.
402 ///
403 /// This option has no effect on file-backed memory maps.
404 ///
405 /// # Example
406 ///
407 /// ```
408 /// use memmap2::MmapOptions;
409 ///
410 /// # fn main() -> std::io::Result<()> {
411 /// let stack = MmapOptions::new().huge(Some(21)).len(2*1024*1024).map_anon();
412 /// # Ok(())
413 /// # }
414 /// ```
415 ///
416 /// The number 21 corresponds to `MAP_HUGE_2MB`. See mmap(2) for more details.
417 pub fn huge(&mut self, page_bits: Option<u8>) -> &mut Self {
418 self.huge = Some(page_bits.unwrap_or(0));
419 self
420 }
421
422 /// Populate (prefault) page tables for a mapping.
423 ///
424 /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later.
425 ///
426 /// This option corresponds to the `MAP_POPULATE` flag on Linux. It has no effect on Windows.
427 ///
428 /// # Example
429 ///
430 /// ```
431 /// use memmap2::MmapOptions;
432 /// use std::fs::File;
433 ///
434 /// # fn main() -> std::io::Result<()> {
435 /// let file = File::open("LICENSE-MIT")?;
436 ///
437 /// let mmap = unsafe {
438 /// MmapOptions::new().populate().map(&file)?
439 /// };
440 ///
441 /// assert_eq!(&b"Copyright"[..], &mmap[..9]);
442 /// # Ok(())
443 /// # }
444 /// ```
445 pub fn populate(&mut self) -> &mut Self {
446 self.populate = true;
447 self
448 }
449
450 /// Do not reserve swap space for the memory map.
451 ///
452 /// By default, platforms may reserve swap space for memory maps.
453 /// This guarantees that a write to the mapped memory will succeed, even if physical memory is exhausted.
454 /// Otherwise, the write to memory could fail (on Linux with a segfault).
455 ///
456 /// This option requests that no swap space will be allocated for the memory map,
457 /// which can be useful for extremely large maps that are only written to sparsely.
458 ///
459 /// This option is currently supported on Linux, Android, Apple platforms (macOS, iOS, visionOS, etc.), NetBSD, Solaris and Illumos.
460 /// On those platforms, this option corresponds to the `MAP_NORESERVE` flag.
461 /// On Linux, this option is ignored if [`vm.overcommit_memory`](https://www.kernel.org/doc/Documentation/vm/overcommit-accounting) is set to 2.
462 ///
463 /// # Example
464 ///
465 /// ```
466 /// use memmap2::MmapOptions;
467 /// use std::fs::File;
468 ///
469 /// # fn main() -> std::io::Result<()> {
470 /// let file = File::open("LICENSE-MIT")?;
471 ///
472 /// let mmap = unsafe {
473 /// MmapOptions::new().no_reserve_swap().map_copy(&file)?
474 /// };
475 ///
476 /// assert_eq!(&b"Copyright"[..], &mmap[..9]);
477 /// # Ok(())
478 /// # }
479 /// ```
480 pub fn no_reserve_swap(&mut self) -> &mut Self {
481 self.no_reserve_swap = true;
482 self
483 }
484
485 /// Do not probe the file handle for the widest supported protection
486 /// level when creating the mapping.
487 ///
488 /// This option only has an effect on Windows. There, by default,
489 /// creating a mapping issues up to two extra `CreateFileMappingW` calls
490 /// to discover whether the handle supports write and/or execute access,
491 /// so that the underlying section is created with the widest protection
492 /// the handle supports and the mapping can later be transitioned, e.g.
493 /// with [`Mmap::make_mut()`].
494 ///
495 /// With this option set, the section and view are created with exactly
496 /// the protection the mapping type requires (e.g. `PAGE_READONLY` and
497 /// `FILE_MAP_READ` for [`map()`][MmapOptions::map]). This guarantees a
498 /// read-only mapping never creates a writable section on the file, but
499 /// transitioning the returned mapping to a wider protection will fail.
500 ///
501 /// # Example
502 ///
503 /// ```
504 /// use memmap2::MmapOptions;
505 /// use std::fs::File;
506 ///
507 /// # fn main() -> std::io::Result<()> {
508 /// let file = File::open("LICENSE-MIT")?;
509 ///
510 /// let mmap = unsafe {
511 /// MmapOptions::new().no_probe_handle().map(&file)?
512 /// };
513 ///
514 /// assert_eq!(&b"Copyright"[..], &mmap[..9]);
515 /// # Ok(())
516 /// # }
517 /// ```
518 pub fn no_probe_handle(&mut self) -> &mut Self {
519 self.no_probe_handle = true;
520 self
521 }
522
523 /// Creates a read-only memory map backed by a file.
524 ///
525 /// # Safety
526 ///
527 /// See the [type-level][MmapOptions] docs for why this function is unsafe.
528 ///
529 /// # Errors
530 ///
531 /// This method returns an error when the underlying system call fails, which can happen for a
532 /// variety of reasons, such as when the file is not open with read permissions.
533 ///
534 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
535 ///
536 /// # Example
537 ///
538 /// ```
539 /// use memmap2::MmapOptions;
540 /// use std::fs::File;
541 /// use std::io::Read;
542 ///
543 /// # fn main() -> std::io::Result<()> {
544 /// let mut file = File::open("LICENSE-APACHE")?;
545 ///
546 /// let mut contents = Vec::new();
547 /// file.read_to_end(&mut contents)?;
548 ///
549 /// let mmap = unsafe {
550 /// MmapOptions::new().map(&file)?
551 /// };
552 ///
553 /// assert_eq!(&contents[..], &mmap[..]);
554 /// # Ok(())
555 /// # }
556 /// ```
557 pub unsafe fn map<T: MmapAsRawDesc>(&self, file: T) -> std::io::Result<Mmap> {
558 let desc = file.as_raw_desc();
559
560 MmapInner::map(
561 self.get_len(&file)?,
562 desc.0,
563 self.offset,
564 self.populate,
565 self.no_reserve_swap,
566 !self.no_probe_handle,
567 )
568 .map(|inner| Mmap { inner })
569 }
570
571 /// Creates a readable and executable memory map backed by a file.
572 ///
573 /// # Safety
574 ///
575 /// See the [type-level][MmapOptions] docs for why this function is unsafe.
576 ///
577 /// # Errors
578 ///
579 /// This method returns an error when the underlying system call fails, which can happen for a
580 /// variety of reasons, such as when the file is not open with read permissions.
581 ///
582 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
583 pub unsafe fn map_exec<T: MmapAsRawDesc>(&self, file: T) -> std::io::Result<Mmap> {
584 let desc = file.as_raw_desc();
585
586 MmapInner::map_exec(
587 self.get_len(&file)?,
588 desc.0,
589 self.offset,
590 self.populate,
591 self.no_reserve_swap,
592 !self.no_probe_handle,
593 )
594 .map(|inner| Mmap { inner })
595 }
596
597 /// Creates a writeable memory map backed by a file.
598 ///
599 /// # Safety
600 ///
601 /// See the [type-level][MmapOptions] docs for why this function is unsafe.
602 ///
603 /// # Errors
604 ///
605 /// This method returns an error when the underlying system call fails, which can happen for a
606 /// variety of reasons, such as when the file is not open with read and write permissions.
607 ///
608 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
609 ///
610 /// # Example
611 ///
612 /// ```
613 /// use std::fs::OpenOptions;
614 /// use std::path::PathBuf;
615 ///
616 /// use memmap2::MmapOptions;
617 /// #
618 /// # fn main() -> std::io::Result<()> {
619 /// # let tempdir = tempfile::tempdir()?;
620 /// let path: PathBuf = /* path to file */
621 /// # tempdir.path().join("map_mut");
622 /// let file = OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&path)?;
623 /// file.set_len(13)?;
624 ///
625 /// let mut mmap = unsafe {
626 /// MmapOptions::new().map_mut(&file)?
627 /// };
628 ///
629 /// mmap.copy_from_slice(b"Hello, world!");
630 /// # Ok(())
631 /// # }
632 /// ```
633 pub unsafe fn map_mut<T: MmapAsRawDesc>(&self, file: T) -> std::io::Result<MmapMut> {
634 let desc = file.as_raw_desc();
635
636 MmapInner::map_mut(
637 self.get_len(&file)?,
638 desc.0,
639 self.offset,
640 self.populate,
641 self.no_reserve_swap,
642 !self.no_probe_handle,
643 )
644 .map(|inner| MmapMut { inner })
645 }
646
647 /// Creates a copy-on-write memory map backed by a file.
648 ///
649 /// Data written to the memory map will not be visible by other processes,
650 /// and will not be carried through to the underlying file.
651 ///
652 /// # Safety
653 ///
654 /// See the [type-level][MmapOptions] docs for why this function is unsafe.
655 ///
656 /// # Errors
657 ///
658 /// This method returns an error when the underlying system call fails, which can happen for a
659 /// variety of reasons, such as when the file is not open with writable permissions.
660 ///
661 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
662 ///
663 /// # Example
664 ///
665 /// ```
666 /// use memmap2::MmapOptions;
667 /// use std::fs::File;
668 /// use std::io::Write;
669 ///
670 /// # fn main() -> std::io::Result<()> {
671 /// let file = File::open("LICENSE-APACHE")?;
672 /// let mut mmap = unsafe { MmapOptions::new().map_copy(&file)? };
673 /// (&mut mmap[..]).write_all(b"Hello, world!")?;
674 /// # Ok(())
675 /// # }
676 /// ```
677 pub unsafe fn map_copy<T: MmapAsRawDesc>(&self, file: T) -> std::io::Result<MmapMut> {
678 let desc = file.as_raw_desc();
679
680 MmapInner::map_copy(
681 self.get_len(&file)?,
682 desc.0,
683 self.offset,
684 self.populate,
685 self.no_reserve_swap,
686 !self.no_probe_handle,
687 )
688 .map(|inner| MmapMut { inner })
689 }
690
691 /// Creates a copy-on-write read-only memory map backed by a file.
692 ///
693 /// # Safety
694 ///
695 /// See the [type-level][MmapOptions] docs for why this function is unsafe.
696 ///
697 /// # Errors
698 ///
699 /// This method returns an error when the underlying system call fails, which can happen for a
700 /// variety of reasons, such as when the file is not open with read permissions.
701 ///
702 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
703 ///
704 /// # Example
705 ///
706 /// ```
707 /// use memmap2::MmapOptions;
708 /// use std::fs::File;
709 /// use std::io::Read;
710 ///
711 /// # fn main() -> std::io::Result<()> {
712 /// let mut file = File::open("README.md")?;
713 ///
714 /// let mut contents = Vec::new();
715 /// file.read_to_end(&mut contents)?;
716 ///
717 /// let mmap = unsafe {
718 /// MmapOptions::new().map_copy_read_only(&file)?
719 /// };
720 ///
721 /// assert_eq!(&contents[..], &mmap[..]);
722 /// # Ok(())
723 /// # }
724 /// ```
725 pub unsafe fn map_copy_read_only<T: MmapAsRawDesc>(&self, file: T) -> std::io::Result<Mmap> {
726 let desc = file.as_raw_desc();
727
728 MmapInner::map_copy_read_only(
729 self.get_len(&file)?,
730 desc.0,
731 self.offset,
732 self.populate,
733 self.no_reserve_swap,
734 !self.no_probe_handle,
735 )
736 .map(|inner| Mmap { inner })
737 }
738
739 /// Creates a read-only memory map backed by a file, after
740 /// verifying that the backing file is immutable.
741 ///
742 /// Unlike [`map()`], this method is not `unsafe` because it verifies that
743 /// the underlying file cannot be modified or truncated. The mapped region
744 /// must fit within the current file size.
745 ///
746 /// Returns `Ok(None)` if the file cannot be proven immutable (including
747 /// on platforms where this check is not supported). Returns `Err` only
748 /// for unexpected I/O errors.
749 ///
750 /// Currently, immutability is recognized on Linux, Android, and FreeBSD
751 /// via:
752 ///
753 /// - A memfd sealed with at least `F_SEAL_SHRINK` and `F_SEAL_WRITE`, or
754 /// - A file with fs-verity enabled (Linux and Android only).
755 ///
756 /// [`map()`]: MmapOptions::map()
757 pub fn map_if_safe<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap, MapIfSafeError> {
758 let desc = file.as_raw_desc();
759 let len = self
760 .get_len(&file)
761 .map_err(MapIfSafeError::new_map_failed)?;
762 MmapInner::check_safe_to_map(desc.0, self.offset, len)?;
763 MmapInner::map(
764 len,
765 desc.0,
766 self.offset,
767 self.populate,
768 self.no_reserve_swap,
769 !self.no_probe_handle,
770 )
771 .map_err(MapIfSafeError::new_map_failed)
772 .map(|inner| Mmap { inner })
773 }
774
775 /// Creates an anonymous memory map.
776 ///
777 /// The memory map length should be configured using [`MmapOptions::len()`]
778 /// before creating an anonymous memory map, otherwise a zero-length mapping
779 /// will be created.
780 ///
781 /// # Errors
782 ///
783 /// This method returns an error when the underlying system call fails or
784 /// when `len > isize::MAX`.
785 ///
786 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
787 pub fn map_anon(&self) -> std::io::Result<MmapMut> {
788 let len = self.len.unwrap_or(0);
789
790 // See get_len() for details.
791 let len = Self::validate_len(len as u64)?;
792
793 MmapInner::map_anon(
794 len,
795 self.stack,
796 self.populate,
797 self.huge,
798 self.no_reserve_swap,
799 )
800 .map(|inner| MmapMut { inner })
801 }
802
803 /// Creates a raw memory map.
804 ///
805 /// # Errors
806 ///
807 /// This method returns an error when the underlying system call fails, which can happen for a
808 /// variety of reasons, such as when the file is not open with read and write permissions.
809 ///
810 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
811 pub fn map_raw<T: MmapAsRawDesc>(&self, file: T) -> std::io::Result<MmapRaw> {
812 let desc = file.as_raw_desc();
813
814 MmapInner::map_mut(
815 self.get_len(&file)?,
816 desc.0,
817 self.offset,
818 self.populate,
819 self.no_reserve_swap,
820 !self.no_probe_handle,
821 )
822 .map(|inner| MmapRaw { inner })
823 }
824
825 /// Creates a read-only raw memory map
826 ///
827 /// This is primarily useful to avoid intermediate `Mmap` instances when
828 /// read-only access to files modified elsewhere are required.
829 ///
830 /// # Errors
831 ///
832 /// This method returns an error when the underlying system call fails.
833 ///
834 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
835 pub fn map_raw_read_only<T: MmapAsRawDesc>(&self, file: T) -> std::io::Result<MmapRaw> {
836 let desc = file.as_raw_desc();
837
838 MmapInner::map(
839 self.get_len(&file)?,
840 desc.0,
841 self.offset,
842 self.populate,
843 self.no_reserve_swap,
844 !self.no_probe_handle,
845 )
846 .map(|inner| MmapRaw { inner })
847 }
848}
849
850/// A handle to an immutable memory mapped buffer.
851///
852/// A `Mmap` may be backed by a file, or it can be anonymous map, backed by volatile memory. Use
853/// [`MmapOptions`] or [`map()`] to create a file-backed memory map. To create an immutable
854/// anonymous memory map, first create a mutable anonymous memory map, and then make it immutable
855/// with [`MmapMut::make_read_only()`].
856///
857/// A file backed `Mmap` is created by `&File` reference, and will remain valid even after the
858/// `File` is dropped. In other words, the `Mmap` handle is completely independent of the `File`
859/// used to create it. For consistency, on some platforms this is achieved by duplicating the
860/// underlying file handle. The memory will be unmapped when the `Mmap` handle is dropped.
861///
862/// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping
863/// the mapped pages into physical memory) though the details of this are platform specific.
864///
865/// `Mmap` is [`Sync`] and [`Send`].
866///
867/// See [`MmapMut`] for the mutable version.
868///
869/// ## Safety
870///
871/// All file-backed memory map constructors are marked `unsafe` because of the potential for
872/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
873/// out of process. Applications must consider the risk and take appropriate precautions when using
874/// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked)
875/// files exist but are platform specific and limited.
876///
877/// ## Example
878///
879/// ```
880/// use memmap2::MmapOptions;
881/// use std::io::Write;
882/// use std::fs::File;
883///
884/// # fn main() -> std::io::Result<()> {
885/// let file = File::open("README.md")?;
886/// let mmap = unsafe { MmapOptions::new().map(&file)? };
887/// assert_eq!(b"# memmap2", &mmap[0..9]);
888/// # Ok(())
889/// # }
890/// ```
891///
892/// [`map()`]: Mmap::map()
893pub struct Mmap {
894 inner: MmapInner,
895}
896
897impl Mmap {
898 /// Creates a read-only memory map backed by a file.
899 ///
900 /// This is equivalent to calling `MmapOptions::new().map(file)`.
901 ///
902 /// # Safety
903 ///
904 /// See the [type-level][Mmap] docs for why this function is unsafe.
905 ///
906 /// # Errors
907 ///
908 /// This method returns an error when the underlying system call fails, which can happen for a
909 /// variety of reasons, such as when the file is not open with read permissions.
910 ///
911 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
912 ///
913 /// # Example
914 ///
915 /// ```
916 /// use std::fs::File;
917 /// use std::io::Read;
918 ///
919 /// use memmap2::Mmap;
920 ///
921 /// # fn main() -> std::io::Result<()> {
922 /// let mut file = File::open("LICENSE-APACHE")?;
923 ///
924 /// let mut contents = Vec::new();
925 /// file.read_to_end(&mut contents)?;
926 ///
927 /// let mmap = unsafe { Mmap::map(&file)? };
928 ///
929 /// assert_eq!(&contents[..], &mmap[..]);
930 /// # Ok(())
931 /// # }
932 /// ```
933 pub unsafe fn map<T: MmapAsRawDesc>(file: T) -> std::io::Result<Mmap> {
934 // SAFETY: safety requirements forwarded to caller.
935 unsafe { MmapOptions::new().map(file) }
936 }
937
938 /// Creates a read-only memory map backed by a file, verifying that the
939 /// file is immutable.
940 ///
941 /// This is equivalent to calling `MmapOptions::new().map_if_safe(file)`.
942 /// See [`MmapOptions::map_if_safe()`] for details.
943 pub fn map_if_safe<T: MmapAsRawDesc>(file: T) -> Result<Mmap, MapIfSafeError> {
944 MmapOptions::new().map_if_safe(file)
945 }
946
947 /// Transition the memory map to be writable.
948 ///
949 /// If the memory map is file-backed, the file must have been opened with write permissions.
950 ///
951 /// # Errors
952 ///
953 /// This method returns an error when the underlying system call fails, which can happen for a
954 /// variety of reasons, such as when the file is not open with writable permissions.
955 ///
956 /// # Example
957 ///
958 /// ```
959 /// use memmap2::Mmap;
960 /// use std::ops::DerefMut;
961 /// use std::io::Write;
962 /// # use std::fs::OpenOptions;
963 ///
964 /// # fn main() -> std::io::Result<()> {
965 /// # let tempdir = tempfile::tempdir()?;
966 /// let file = /* file opened with write permissions */
967 /// # OpenOptions::new()
968 /// # .read(true)
969 /// # .write(true)
970 /// # .create(true)
971 /// # .truncate(true)
972 /// # .open(tempdir.path()
973 /// # .join("make_mut"))?;
974 /// # file.set_len(128)?;
975 /// let mmap = unsafe { Mmap::map(&file)? };
976 /// // ... use the read-only memory map ...
977 /// let mut mut_mmap = mmap.make_mut()?;
978 /// mut_mmap.deref_mut().write_all(b"hello, world!")?;
979 /// # Ok(())
980 /// # }
981 /// ```
982 pub fn make_mut(mut self) -> std::io::Result<MmapMut> {
983 self.inner.make_mut()?;
984 Ok(MmapMut { inner: self.inner })
985 }
986
987 /// Advise OS how this memory map will be accessed.
988 ///
989 /// Only supported on Unix.
990 ///
991 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
992 #[cfg(unix)]
993 pub fn advise(&self, advice: Advice) -> std::io::Result<()> {
994 // SAFETY: The `Advice` enum only allows safe advice values.
995 unsafe {
996 self.inner
997 .advise(advice as libc::c_int, 0, self.inner.len())
998 }
999 }
1000
1001 /// Advise OS how this memory map will be accessed.
1002 ///
1003 /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
1004 ///
1005 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1006 ///
1007 /// # Safety
1008 /// This function can modify the memory map in ways that do not fit in Rust's safe memory access model.
1009 /// Care must be taken not to break the soundness rules of the Rust compiler.
1010 /// Refer to the operating system documentation to see what each of the [`UncheckedAdvice`] variant does.
1011 #[cfg(unix)]
1012 pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> std::io::Result<()> {
1013 // SAFETY: safety requirements forwarded to caller.
1014 unsafe {
1015 self.inner
1016 .advise(advice as libc::c_int, 0, self.inner.len())
1017 }
1018 }
1019
1020 /// Advise OS how this range of memory map will be accessed.
1021 ///
1022 /// Only supported on Unix.
1023 ///
1024 /// The offset and length must be in the bounds of the memory map.
1025 ///
1026 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1027 #[cfg(unix)]
1028 pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> std::io::Result<()> {
1029 // SAFETY: The `Advice` enum only allows safe advice values.
1030 unsafe { self.inner.advise(advice as libc::c_int, offset, len) }
1031 }
1032
1033 /// Advise OS how this range of memory map will be accessed.
1034 ///
1035 /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
1036 ///
1037 /// The offset and length must be in the bounds of the memory map.
1038 ///
1039 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1040 ///
1041 /// # Safety
1042 /// This function can modify the memory map in ways that do not fit in Rust's safe memory access model.
1043 /// Care must be taken not to break the soundness rules of the Rust compiler.
1044 /// Refer to the operating system documentation to see what each of the [`UncheckedAdvice`] variant does.
1045 #[cfg(unix)]
1046 pub unsafe fn unchecked_advise_range(
1047 &self,
1048 advice: UncheckedAdvice,
1049 offset: usize,
1050 len: usize,
1051 ) -> std::io::Result<()> {
1052 // SAFETY: safety requirements forwarded to caller.
1053 unsafe { self.inner.advise(advice as libc::c_int, offset, len) }
1054 }
1055
1056 /// Lock the whole memory map into RAM. Only supported on Unix.
1057 ///
1058 /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
1059 #[cfg(unix)]
1060 pub fn lock(&self) -> std::io::Result<()> {
1061 self.inner.lock()
1062 }
1063
1064 /// Unlock the whole memory map. Only supported on Unix.
1065 ///
1066 /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
1067 #[cfg(unix)]
1068 pub fn unlock(&self) -> std::io::Result<()> {
1069 self.inner.unlock()
1070 }
1071
1072 /// Adjust the size of the memory mapping.
1073 ///
1074 /// This will try to resize the memory mapping in place. If
1075 /// [`RemapOptions::may_move`] is specified it will move the mapping if it
1076 /// could not resize in place, otherwise it will error.
1077 ///
1078 /// Only supported on Linux.
1079 ///
1080 /// See the [`mremap(2)`] man page.
1081 ///
1082 /// # Safety
1083 ///
1084 /// Resizing the memory mapping beyond the end of the mapped file will
1085 /// result in UB should you happen to access memory beyond the end of the
1086 /// file.
1087 ///
1088 /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
1089 #[cfg(target_os = "linux")]
1090 pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> std::io::Result<()> {
1091 self.inner.remap(new_len, options)
1092 }
1093}
1094
1095#[cfg(feature = "stable_deref_trait")]
1096unsafe impl stable_deref_trait::StableDeref for Mmap {}
1097
1098impl Deref for Mmap {
1099 type Target = [u8];
1100
1101 #[inline]
1102 fn deref(&self) -> &[u8] {
1103 unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) }
1104 }
1105}
1106
1107impl AsRef<[u8]> for Mmap {
1108 #[inline]
1109 fn as_ref(&self) -> &[u8] {
1110 self.deref()
1111 }
1112}
1113
1114impl fmt::Debug for Mmap {
1115 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1116 fmt.debug_struct("Mmap")
1117 .field("ptr", &self.as_ptr())
1118 .field("len", &self.len())
1119 .finish()
1120 }
1121}
1122
1123/// A handle to a raw memory mapped buffer.
1124///
1125/// This struct never hands out references to its interior, only raw pointers.
1126/// This can be helpful when creating shared memory maps between untrusted processes.
1127///
1128/// For the safety concerns that arise when converting these raw pointers to references,
1129/// see the [`Mmap`] safety documentation.
1130pub struct MmapRaw {
1131 inner: MmapInner,
1132}
1133
1134impl MmapRaw {
1135 /// Creates a writeable memory map backed by a file.
1136 ///
1137 /// This is equivalent to calling `MmapOptions::new().map_raw(file)`.
1138 ///
1139 /// # Errors
1140 ///
1141 /// This method returns an error when the underlying system call fails, which can happen for a
1142 /// variety of reasons, such as when the file is not open with read and write permissions.
1143 ///
1144 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
1145 pub fn map_raw<T: MmapAsRawDesc>(file: T) -> std::io::Result<MmapRaw> {
1146 MmapOptions::new().map_raw(file)
1147 }
1148
1149 /// Returns a raw pointer to the memory mapped file.
1150 ///
1151 /// Before dereferencing this pointer, you have to make sure that the file has not been
1152 /// truncated since the memory map was created.
1153 /// Avoiding this will not introduce memory safety issues in Rust terms,
1154 /// but will cause SIGBUS (or equivalent) signal.
1155 #[inline]
1156 pub fn as_ptr(&self) -> *const u8 {
1157 self.inner.ptr()
1158 }
1159
1160 /// Returns an unsafe mutable pointer to the memory mapped file.
1161 ///
1162 /// Before dereferencing this pointer, you have to make sure that the file has not been
1163 /// truncated since the memory map was created.
1164 /// Avoiding this will not introduce memory safety issues in Rust terms,
1165 /// but will cause SIGBUS (or equivalent) signal.
1166 #[inline]
1167 pub fn as_mut_ptr(&self) -> *mut u8 {
1168 self.inner.ptr().cast_mut()
1169 }
1170
1171 /// Returns the length in bytes of the memory map.
1172 ///
1173 /// Note that truncating the file can cause the length to change (and render this value unusable).
1174 #[inline]
1175 pub fn len(&self) -> usize {
1176 self.inner.len()
1177 }
1178
1179 /// Flushes outstanding memory map modifications to disk.
1180 ///
1181 /// When this method returns with a non-error result, all outstanding changes to a file-backed
1182 /// memory map are guaranteed to be durably stored. The file's metadata (including last
1183 /// modification timestamp) may not be updated.
1184 ///
1185 /// # Example
1186 ///
1187 /// ```
1188 /// use std::fs::OpenOptions;
1189 /// use std::io::Write;
1190 /// use std::path::PathBuf;
1191 /// use std::slice;
1192 ///
1193 /// use memmap2::MmapRaw;
1194 ///
1195 /// # fn main() -> std::io::Result<()> {
1196 /// let tempdir = tempfile::tempdir()?;
1197 /// let path: PathBuf = /* path to file */
1198 /// # tempdir.path().join("flush");
1199 /// let file = OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&path)?;
1200 /// file.set_len(128)?;
1201 ///
1202 /// let mut mmap = unsafe { MmapRaw::map_raw(&file)? };
1203 ///
1204 /// let mut memory = unsafe { slice::from_raw_parts_mut(mmap.as_mut_ptr(), 128) };
1205 /// memory.write_all(b"Hello, world!")?;
1206 /// mmap.flush()?;
1207 /// # Ok(())
1208 /// # }
1209 /// ```
1210 pub fn flush(&self) -> std::io::Result<()> {
1211 let len = self.len();
1212 self.inner.flush(0, len)
1213 }
1214
1215 /// Asynchronously flushes outstanding memory map modifications to disk.
1216 ///
1217 /// This method initiates flushing modified pages to durable storage, but it will not wait for
1218 /// the operation to complete before returning. The file's metadata (including last
1219 /// modification timestamp) may not be updated.
1220 pub fn flush_async(&self) -> std::io::Result<()> {
1221 let len = self.len();
1222 self.inner.flush_async(0, len)
1223 }
1224
1225 /// Flushes outstanding memory map modifications in the range to disk.
1226 ///
1227 /// The offset and length must be in the bounds of the memory map.
1228 ///
1229 /// When this method returns with a non-error result, all outstanding changes to a file-backed
1230 /// memory in the range are guaranteed to be durable stored. The file's metadata (including
1231 /// last modification timestamp) may not be updated. It is not guaranteed the only the changes
1232 /// in the specified range are flushed; other outstanding changes to the memory map may be
1233 /// flushed as well.
1234 pub fn flush_range(&self, offset: usize, len: usize) -> std::io::Result<()> {
1235 self.inner.flush(offset, len)
1236 }
1237
1238 /// Asynchronously flushes outstanding memory map modifications in the range to disk.
1239 ///
1240 /// The offset and length must be in the bounds of the memory map.
1241 ///
1242 /// This method initiates flushing modified pages to durable storage, but it will not wait for
1243 /// the operation to complete before returning. The file's metadata (including last
1244 /// modification timestamp) may not be updated. It is not guaranteed that the only changes
1245 /// flushed are those in the specified range; other outstanding changes to the memory map may
1246 /// be flushed as well.
1247 pub fn flush_async_range(&self, offset: usize, len: usize) -> std::io::Result<()> {
1248 self.inner.flush_async(offset, len)
1249 }
1250
1251 /// Advise OS how this memory map will be accessed.
1252 ///
1253 /// Only supported on Unix.
1254 ///
1255 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1256 #[cfg(unix)]
1257 pub fn advise(&self, advice: Advice) -> std::io::Result<()> {
1258 // SAFETY: The `Advice` enum only allows safe advice values.
1259 unsafe {
1260 self.inner
1261 .advise(advice as libc::c_int, 0, self.inner.len())
1262 }
1263 }
1264
1265 /// Advise OS how this memory map will be accessed.
1266 ///
1267 /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
1268 ///
1269 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1270 ///
1271 /// # Safety
1272 /// This function can modify the memory map in ways that do not fit in Rust's safe memory access model.
1273 /// Care must be taken not to break the soundness rules of the Rust compiler.
1274 /// Refer to the operating system documentation to see what each of the [`UncheckedAdvice`] variant does.
1275 #[cfg(unix)]
1276 pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> std::io::Result<()> {
1277 // SAFETY: safety requirements forwarded to caller.
1278 unsafe {
1279 self.inner
1280 .advise(advice as libc::c_int, 0, self.inner.len())
1281 }
1282 }
1283
1284 /// Advise OS how this range of memory map will be accessed.
1285 ///
1286 /// The offset and length must be in the bounds of the memory map.
1287 ///
1288 /// Only supported on Unix.
1289 ///
1290 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1291 #[cfg(unix)]
1292 pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> std::io::Result<()> {
1293 // SAFETY: The `Advice` enum only allows safe advice values.
1294 unsafe { self.inner.advise(advice as libc::c_int, offset, len) }
1295 }
1296
1297 /// Advise OS how this range of memory map will be accessed.
1298 ///
1299 /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
1300 ///
1301 /// The offset and length must be in the bounds of the memory map.
1302 ///
1303 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1304 ///
1305 /// # Safety
1306 /// This function can modify the memory map in ways that do not fit in Rust's safe memory access model.
1307 /// Care must be taken not to break the soundness rules of the Rust compiler.
1308 /// Refer to the operating system documentation to see what each of the [`UncheckedAdvice`] variant does.
1309 #[cfg(unix)]
1310 pub unsafe fn unchecked_advise_range(
1311 &self,
1312 advice: UncheckedAdvice,
1313 offset: usize,
1314 len: usize,
1315 ) -> std::io::Result<()> {
1316 // SAFETY: safety requirements forwarded to caller.
1317 unsafe { self.inner.advise(advice as libc::c_int, offset, len) }
1318 }
1319
1320 /// Lock the whole memory map into RAM. Only supported on Unix.
1321 ///
1322 /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
1323 #[cfg(unix)]
1324 pub fn lock(&self) -> std::io::Result<()> {
1325 self.inner.lock()
1326 }
1327
1328 /// Unlock the whole memory map. Only supported on Unix.
1329 ///
1330 /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
1331 #[cfg(unix)]
1332 pub fn unlock(&self) -> std::io::Result<()> {
1333 self.inner.unlock()
1334 }
1335
1336 /// Adjust the size of the memory mapping.
1337 ///
1338 /// This will try to resize the memory mapping in place. If
1339 /// [`RemapOptions::may_move`] is specified it will move the mapping if it
1340 /// could not resize in place, otherwise it will error.
1341 ///
1342 /// Only supported on Linux.
1343 ///
1344 /// See the [`mremap(2)`] man page.
1345 ///
1346 /// # Safety
1347 ///
1348 /// Resizing the memory mapping beyond the end of the mapped file will
1349 /// result in UB should you happen to access memory beyond the end of the
1350 /// file.
1351 ///
1352 /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
1353 #[cfg(target_os = "linux")]
1354 pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> std::io::Result<()> {
1355 self.inner.remap(new_len, options)
1356 }
1357}
1358
1359impl fmt::Debug for MmapRaw {
1360 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1361 fmt.debug_struct("MmapRaw")
1362 .field("ptr", &self.as_ptr())
1363 .field("len", &self.len())
1364 .finish()
1365 }
1366}
1367
1368impl From<Mmap> for MmapRaw {
1369 fn from(value: Mmap) -> Self {
1370 Self { inner: value.inner }
1371 }
1372}
1373
1374impl From<MmapMut> for MmapRaw {
1375 fn from(value: MmapMut) -> Self {
1376 Self { inner: value.inner }
1377 }
1378}
1379
1380/// A handle to a mutable memory mapped buffer.
1381///
1382/// A file-backed `MmapMut` buffer may be used to read from or write to a file. An anonymous
1383/// `MmapMut` buffer may be used any place that an in-memory byte buffer is needed. Use
1384/// [`MmapMut::map_mut()`] and [`MmapMut::map_anon()`] to create a mutable memory map of the
1385/// respective types, or [`MmapOptions::map_mut()`] and [`MmapOptions::map_anon()`] if non-default
1386/// options are required.
1387///
1388/// A file backed `MmapMut` is created by `&File` reference, and will remain valid even after the
1389/// `File` is dropped. In other words, the `MmapMut` handle is completely independent of the `File`
1390/// used to create it. For consistency, on some platforms this is achieved by duplicating the
1391/// underlying file handle. The memory will be unmapped when the `MmapMut` handle is dropped.
1392///
1393/// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping
1394/// the mapped pages into physical memory) though the details of this are platform specific.
1395///
1396/// `MmapMut` is [`Sync`] and [`Send`].
1397///
1398/// See [`Mmap`] for the immutable version.
1399///
1400/// ## Safety
1401///
1402/// All file-backed memory map constructors are marked `unsafe` because of the potential for
1403/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
1404/// out of process. Applications must consider the risk and take appropriate precautions when using
1405/// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked)
1406/// files exist but are platform specific and limited.
1407pub struct MmapMut {
1408 inner: MmapInner,
1409}
1410
1411impl MmapMut {
1412 /// Creates a writeable memory map backed by a file.
1413 ///
1414 /// This is equivalent to calling `MmapOptions::new().map_mut(file)`.
1415 ///
1416 /// # Safety
1417 ///
1418 /// See the [type-level][MmapMut] docs for why this function is unsafe.
1419 ///
1420 /// # Errors
1421 ///
1422 /// This method returns an error when the underlying system call fails, which can happen for a
1423 /// variety of reasons, such as when the file is not open with read and write permissions.
1424 ///
1425 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
1426 ///
1427 /// # Example
1428 ///
1429 /// ```
1430 /// use std::fs::OpenOptions;
1431 /// use std::path::PathBuf;
1432 ///
1433 /// use memmap2::MmapMut;
1434 /// #
1435 /// # fn main() -> std::io::Result<()> {
1436 /// # let tempdir = tempfile::tempdir()?;
1437 /// let path: PathBuf = /* path to file */
1438 /// # tempdir.path().join("map_mut");
1439 /// let file = OpenOptions::new()
1440 /// .read(true)
1441 /// .write(true)
1442 /// .create(true)
1443 /// .truncate(true)
1444 /// .open(&path)?;
1445 /// file.set_len(13)?;
1446 ///
1447 /// let mut mmap = unsafe { MmapMut::map_mut(&file)? };
1448 ///
1449 /// mmap.copy_from_slice(b"Hello, world!");
1450 /// # Ok(())
1451 /// # }
1452 /// ```
1453 pub unsafe fn map_mut<T: MmapAsRawDesc>(file: T) -> std::io::Result<MmapMut> {
1454 // SAFETY: safety requirements forwarded to caller.
1455 unsafe { MmapOptions::new().map_mut(file) }
1456 }
1457
1458 /// Creates an anonymous memory map.
1459 ///
1460 /// This is equivalent to calling `MmapOptions::new().len(length).map_anon()`.
1461 ///
1462 /// # Errors
1463 ///
1464 /// This method returns an error when the underlying system call fails or
1465 /// when `len > isize::MAX`.
1466 ///
1467 /// Returns [`ErrorKind::Unsupported`] on unsupported platforms.
1468 pub fn map_anon(length: usize) -> std::io::Result<MmapMut> {
1469 MmapOptions::new().len(length).map_anon()
1470 }
1471
1472 /// Flushes outstanding memory map modifications to disk.
1473 ///
1474 /// When this method returns with a non-error result, all outstanding changes to a file-backed
1475 /// memory map are guaranteed to be durably stored. The file's metadata (including last
1476 /// modification timestamp) may not be updated.
1477 ///
1478 /// # Example
1479 ///
1480 /// ```
1481 /// use std::fs::OpenOptions;
1482 /// use std::io::Write;
1483 /// use std::path::PathBuf;
1484 ///
1485 /// use memmap2::MmapMut;
1486 ///
1487 /// # fn main() -> std::io::Result<()> {
1488 /// # let tempdir = tempfile::tempdir()?;
1489 /// let path: PathBuf = /* path to file */
1490 /// # tempdir.path().join("flush");
1491 /// let file = OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&path)?;
1492 /// file.set_len(128)?;
1493 ///
1494 /// let mut mmap = unsafe { MmapMut::map_mut(&file)? };
1495 ///
1496 /// (&mut mmap[..]).write_all(b"Hello, world!")?;
1497 /// mmap.flush()?;
1498 /// # Ok(())
1499 /// # }
1500 /// ```
1501 pub fn flush(&self) -> std::io::Result<()> {
1502 let len = self.len();
1503 self.inner.flush(0, len)
1504 }
1505
1506 /// Asynchronously flushes outstanding memory map modifications to disk.
1507 ///
1508 /// This method initiates flushing modified pages to durable storage, but it will not wait for
1509 /// the operation to complete before returning. The file's metadata (including last
1510 /// modification timestamp) may not be updated.
1511 pub fn flush_async(&self) -> std::io::Result<()> {
1512 let len = self.len();
1513 self.inner.flush_async(0, len)
1514 }
1515
1516 /// Flushes outstanding memory map modifications in the range to disk.
1517 ///
1518 /// The offset and length must be in the bounds of the memory map.
1519 ///
1520 /// When this method returns with a non-error result, all outstanding changes to a file-backed
1521 /// memory in the range are guaranteed to be durable stored. The file's metadata (including
1522 /// last modification timestamp) may not be updated. It is not guaranteed the only the changes
1523 /// in the specified range are flushed; other outstanding changes to the memory map may be
1524 /// flushed as well.
1525 pub fn flush_range(&self, offset: usize, len: usize) -> std::io::Result<()> {
1526 self.inner.flush(offset, len)
1527 }
1528
1529 /// Asynchronously flushes outstanding memory map modifications in the range to disk.
1530 ///
1531 /// The offset and length must be in the bounds of the memory map.
1532 ///
1533 /// This method initiates flushing modified pages to durable storage, but it will not wait for
1534 /// the operation to complete before returning. The file's metadata (including last
1535 /// modification timestamp) may not be updated. It is not guaranteed that the only changes
1536 /// flushed are those in the specified range; other outstanding changes to the memory map may
1537 /// be flushed as well.
1538 pub fn flush_async_range(&self, offset: usize, len: usize) -> std::io::Result<()> {
1539 self.inner.flush_async(offset, len)
1540 }
1541
1542 /// Returns an immutable version of this memory mapped buffer.
1543 ///
1544 /// If the memory map is file-backed, the file must have been opened with read permissions.
1545 ///
1546 /// # Errors
1547 ///
1548 /// This method returns an error when the underlying system call fails, which can happen for a
1549 /// variety of reasons, such as when the file has not been opened with read permissions.
1550 ///
1551 /// # Example
1552 ///
1553 /// ```
1554 /// use std::io::Write;
1555 /// use std::path::PathBuf;
1556 ///
1557 /// use memmap2::{Mmap, MmapMut};
1558 ///
1559 /// # fn main() -> std::io::Result<()> {
1560 /// let mut mmap = MmapMut::map_anon(128)?;
1561 ///
1562 /// (&mut mmap[..]).write(b"Hello, world!")?;
1563 ///
1564 /// let mmap: Mmap = mmap.make_read_only()?;
1565 /// # Ok(())
1566 /// # }
1567 /// ```
1568 pub fn make_read_only(mut self) -> std::io::Result<Mmap> {
1569 self.inner.make_read_only()?;
1570 Ok(Mmap { inner: self.inner })
1571 }
1572
1573 /// Transition the memory map to be readable and executable.
1574 ///
1575 /// If the memory map is file-backed, the file must have been opened with execute permissions.
1576 ///
1577 /// On systems with separate instructions and data caches (a category that includes many ARM
1578 /// chips), a platform-specific call may be needed to ensure that the changes are visible to the
1579 /// execution unit (e.g. when using this function to implement a JIT compiler). For more
1580 /// details, see [this ARM write-up](https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/caches-and-self-modifying-code)
1581 /// or the `man` page for [`sys_icache_invalidate`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sys_icache_invalidate.3.html).
1582 ///
1583 /// # Errors
1584 ///
1585 /// This method returns an error when the underlying system call fails, which can happen for a
1586 /// variety of reasons, such as when the file has not been opened with execute permissions.
1587 pub fn make_exec(mut self) -> std::io::Result<Mmap> {
1588 self.inner.make_exec()?;
1589 Ok(Mmap { inner: self.inner })
1590 }
1591
1592 /// Advise OS how this memory map will be accessed.
1593 ///
1594 /// Only supported on Unix.
1595 ///
1596 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1597 #[cfg(unix)]
1598 pub fn advise(&self, advice: Advice) -> std::io::Result<()> {
1599 // SAFETY: The `Advice` enum only allows safe advice values.
1600 unsafe {
1601 self.inner
1602 .advise(advice as libc::c_int, 0, self.inner.len())
1603 }
1604 }
1605
1606 /// Advise OS how this memory map will be accessed.
1607 ///
1608 /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
1609 ///
1610 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1611 #[cfg(unix)]
1612 pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> std::io::Result<()> {
1613 // SAFETY: Safety requirements pushed to caller.
1614 unsafe {
1615 self.inner
1616 .advise(advice as libc::c_int, 0, self.inner.len())
1617 }
1618 }
1619
1620 /// Advise OS how this range of memory map will be accessed.
1621 ///
1622 /// Only supported on Unix.
1623 ///
1624 /// The offset and length must be in the bounds of the memory map.
1625 ///
1626 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1627 #[cfg(unix)]
1628 pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> std::io::Result<()> {
1629 // SAFETY: The `Advice` enum only allows safe advice values.
1630 unsafe { self.inner.advise(advice as libc::c_int, offset, len) }
1631 }
1632
1633 /// Advise OS how this range of memory map will be accessed.
1634 ///
1635 /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
1636 ///
1637 /// The offset and length must be in the bounds of the memory map.
1638 ///
1639 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1640 #[cfg(unix)]
1641 pub unsafe fn unchecked_advise_range(
1642 &self,
1643 advice: UncheckedAdvice,
1644 offset: usize,
1645 len: usize,
1646 ) -> std::io::Result<()> {
1647 // SAFETY: Safety requirements pushed to caller.
1648 unsafe { self.inner.advise(advice as libc::c_int, offset, len) }
1649 }
1650
1651 /// Lock the whole memory map into RAM. Only supported on Unix.
1652 ///
1653 /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
1654 #[cfg(unix)]
1655 pub fn lock(&self) -> std::io::Result<()> {
1656 self.inner.lock()
1657 }
1658
1659 /// Unlock the whole memory map. Only supported on Unix.
1660 ///
1661 /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
1662 #[cfg(unix)]
1663 pub fn unlock(&self) -> std::io::Result<()> {
1664 self.inner.unlock()
1665 }
1666
1667 /// Adjust the size of the memory mapping.
1668 ///
1669 /// This will try to resize the memory mapping in place. If
1670 /// [`RemapOptions::may_move`] is specified it will move the mapping if it
1671 /// could not resize in place, otherwise it will error.
1672 ///
1673 /// Only supported on Linux.
1674 ///
1675 /// See the [`mremap(2)`] man page.
1676 ///
1677 /// # Safety
1678 ///
1679 /// Resizing the memory mapping beyond the end of the mapped file will
1680 /// result in UB should you happen to access memory beyond the end of the
1681 /// file.
1682 ///
1683 /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
1684 #[cfg(target_os = "linux")]
1685 pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> std::io::Result<()> {
1686 self.inner.remap(new_len, options)
1687 }
1688}
1689
1690#[cfg(feature = "stable_deref_trait")]
1691unsafe impl stable_deref_trait::StableDeref for MmapMut {}
1692
1693impl Deref for MmapMut {
1694 type Target = [u8];
1695
1696 #[inline]
1697 fn deref(&self) -> &[u8] {
1698 unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) }
1699 }
1700}
1701
1702impl DerefMut for MmapMut {
1703 #[inline]
1704 fn deref_mut(&mut self) -> &mut [u8] {
1705 unsafe { slice::from_raw_parts_mut(self.inner.mut_ptr(), self.inner.len()) }
1706 }
1707}
1708
1709impl AsRef<[u8]> for MmapMut {
1710 #[inline]
1711 fn as_ref(&self) -> &[u8] {
1712 self.deref()
1713 }
1714}
1715
1716impl AsMut<[u8]> for MmapMut {
1717 #[inline]
1718 fn as_mut(&mut self) -> &mut [u8] {
1719 self.deref_mut()
1720 }
1721}
1722
1723impl fmt::Debug for MmapMut {
1724 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1725 fmt.debug_struct("MmapMut")
1726 .field("ptr", &self.as_ptr())
1727 .field("len", &self.len())
1728 .finish()
1729 }
1730}
1731
1732/// Options for [`Mmap::remap`] and [`MmapMut::remap`].
1733#[derive(Copy, Clone, Default, Debug)]
1734#[cfg(target_os = "linux")]
1735pub struct RemapOptions {
1736 may_move: bool,
1737}
1738
1739#[cfg(target_os = "linux")]
1740impl RemapOptions {
1741 /// Creates a mew set of options for resizing a memory map.
1742 pub fn new() -> Self {
1743 Self::default()
1744 }
1745
1746 /// Controls whether the memory map can be moved if it is not possible to
1747 /// resize it in place.
1748 ///
1749 /// If false then the memory map is guaranteed to remain at the same
1750 /// address when being resized but attempting to resize will return an
1751 /// error if the new memory map would overlap with something else in the
1752 /// current process' memory.
1753 ///
1754 /// By default this is false.
1755 ///
1756 /// # `may_move` and `StableDeref`
1757 /// If the `stable_deref_trait` feature is enabled then [`Mmap`] and
1758 /// [`MmapMut`] implement `StableDeref`. `StableDeref` promises that the
1759 /// memory map dereferences to a fixed address, however, calling `remap`
1760 /// with `may_move` set may result in the backing memory of the mapping
1761 /// being moved to a new address. This may cause UB in other code
1762 /// depending on the `StableDeref` guarantees.
1763 pub fn may_move(mut self, may_move: bool) -> Self {
1764 self.may_move = may_move;
1765 self
1766 }
1767
1768 pub(crate) fn into_flags(self) -> libc::c_int {
1769 if self.may_move {
1770 libc::MREMAP_MAYMOVE
1771 } else {
1772 0
1773 }
1774 }
1775}