Skip to main content

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}