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