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