summaryrefslogtreecommitdiffstats
path: root/third_party/rust/memmap
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/memmap')
-rw-r--r--third_party/rust/memmap/.cargo-checksum.json1
-rw-r--r--third_party/rust/memmap/Cargo.toml33
-rw-r--r--third_party/rust/memmap/LICENSE-APACHE201
-rw-r--r--third_party/rust/memmap/LICENSE-MIT25
-rw-r--r--third_party/rust/memmap/README.md53
-rw-r--r--third_party/rust/memmap/ci/install.sh47
-rw-r--r--third_party/rust/memmap/ci/script.sh20
-rw-r--r--third_party/rust/memmap/examples/cat.rs23
-rw-r--r--third_party/rust/memmap/src/lib.rs1008
-rw-r--r--third_party/rust/memmap/src/unix.rs214
-rw-r--r--third_party/rust/memmap/src/windows.rs300
11 files changed, 1925 insertions, 0 deletions
diff --git a/third_party/rust/memmap/.cargo-checksum.json b/third_party/rust/memmap/.cargo-checksum.json
new file mode 100644
index 0000000000..6fda693661
--- /dev/null
+++ b/third_party/rust/memmap/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"4f6e813f7480758c57f9d180ade1276761a499245846fadb7a96a234342506ca","LICENSE-APACHE":"04ea4849dba9dcae07113850c6f1b1a69052c625210639914eee352023f750ad","LICENSE-MIT":"bd1d8f06a6ce1f7645991e347b95864b970eed43624305eb4bb78c09aef8692d","README.md":"193c46fdc56e4ca953ec7179bf4fd5f302b46557d86181b56b7d6294f25eaa96","ci/install.sh":"8841985e8645d391829ba52cd669bc5c5d98b1fdd8979c7cfd3cd3573c4a0a4b","ci/script.sh":"04127e49ac7346941f0a21d2e1a9177719e62f1e92755579c3601fc98e33006c","examples/cat.rs":"86cfee28482f92ea4c4ae4ebdff97d70fc095208cc5de09db39994118468d1ff","src/lib.rs":"82e116f2b1fbfc7e987a0dfde7e73e51b231f38f33b76369c6de0d46b63c60e1","src/unix.rs":"93fb4fe71dd04e2d1c5e1b6a285bce8b729456bdddbd758aa6768e8ab30ed143","src/windows.rs":"21566160bc1b2f2f82988b9e1274b3b700034cad0e5ca723695863a432da4896"},"package":"6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"} \ No newline at end of file
diff --git a/third_party/rust/memmap/Cargo.toml b/third_party/rust/memmap/Cargo.toml
new file mode 100644
index 0000000000..fef331e356
--- /dev/null
+++ b/third_party/rust/memmap/Cargo.toml
@@ -0,0 +1,33 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g. crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "memmap"
+version = "0.7.0"
+authors = ["Dan Burkert <dan@danburkert.com>"]
+description = "Cross-platform Rust API for memory-mapped file IO"
+documentation = "https://docs.rs/memmap"
+keywords = ["mmap", "memory-map", "io", "file"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/danburkert/memmap-rs"
+[dev-dependencies.tempdir]
+version = "0.3"
+[target."cfg(unix)".dependencies.libc]
+version = "0.2"
+[target."cfg(windows)".dependencies.winapi]
+version = "0.3"
+features = ["basetsd", "handleapi", "memoryapi", "minwindef", "std", "sysinfoapi"]
+[badges.appveyor]
+repository = "danburkert/mmap"
+
+[badges.travis-ci]
+repository = "danburkert/memmap-rs"
diff --git a/third_party/rust/memmap/LICENSE-APACHE b/third_party/rust/memmap/LICENSE-APACHE
new file mode 100644
index 0000000000..7be3d81ac7
--- /dev/null
+++ b/third_party/rust/memmap/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [2015] [Dan Burkert]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust/memmap/LICENSE-MIT b/third_party/rust/memmap/LICENSE-MIT
new file mode 100644
index 0000000000..ebb42e1f3e
--- /dev/null
+++ b/third_party/rust/memmap/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2015 Dan Burkert
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/memmap/README.md b/third_party/rust/memmap/README.md
new file mode 100644
index 0000000000..c230b32062
--- /dev/null
+++ b/third_party/rust/memmap/README.md
@@ -0,0 +1,53 @@
+# memmap
+
+A Rust library for cross-platform memory mapped IO.
+
+[![Build Status](https://travis-ci.org/danburkert/memmap-rs.svg?branch=master)](https://travis-ci.org/danburkert/memmap-rs)
+[![Windows Build Status](https://ci.appveyor.com/api/projects/status/ubka00959pstatkg/branch/master?svg=true)](https://ci.appveyor.com/project/danburkert/mmap)
+[![Documentation](https://docs.rs/memmap/badge.svg)](https://docs.rs/memmap)
+[![Crate](https://img.shields.io/crates/v/memmap.svg)](https://crates.io/crates/memmap)
+
+## Features
+
+- [x] file-backed memory maps
+- [x] anonymous memory maps
+- [x] synchronous and asynchronous flushing
+- [x] copy-on-write memory maps
+- [x] read-only memory maps
+- [x] stack support (`MAP_STACK` on unix)
+- [x] executable memory maps
+- [ ] huge page support
+
+## Platforms
+
+`memmap` should work on any platform supported by
+[`libc`](https://github.com/rust-lang-nursery/libc#platforms-and-documentation).
+`memmap` requires Rust stable 1.13 or greater.
+
+`memmap` is continuously tested on:
+ * `x86_64-unknown-linux-gnu` (Linux)
+ * `i686-unknown-linux-gnu`
+ * `x86_64-unknown-linux-musl` (Linux MUSL)
+ * `x86_64-apple-darwin` (OSX)
+ * `i686-apple-darwin`
+ * `x86_64-pc-windows-msvc` (Windows)
+ * `i686-pc-windows-msvc`
+ * `x86_64-pc-windows-gnu`
+ * `i686-pc-windows-gnu`
+
+`memmap` is continuously cross-compiled against:
+ * `arm-linux-androideabi` (Android)
+ * `aarch64-unknown-linux-gnu` (ARM)
+ * `arm-unknown-linux-gnueabihf`
+ * `mips-unknown-linux-gnu` (MIPS)
+ * `x86_64-apple-ios` (iOS)
+ * `i686-apple-ios`
+
+## License
+
+`memmap` is primarily distributed under the terms of both the MIT license and the
+Apache License (Version 2.0).
+
+See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT) for details.
+
+Copyright (c) 2015 Dan Burkert.
diff --git a/third_party/rust/memmap/ci/install.sh b/third_party/rust/memmap/ci/install.sh
new file mode 100644
index 0000000000..80e18e4720
--- /dev/null
+++ b/third_party/rust/memmap/ci/install.sh
@@ -0,0 +1,47 @@
+set -ex
+
+main() {
+ local target=
+ if [ $TRAVIS_OS_NAME = linux ]; then
+ target=x86_64-unknown-linux-musl
+ sort=sort
+ else
+ target=x86_64-apple-darwin
+ sort=gsort # for `sort --sort-version`, from brew's coreutils.
+ fi
+
+ # Builds for iOS are done on OSX, but require the specific target to be
+ # installed.
+ case $TARGET in
+ aarch64-apple-ios)
+ rustup target install aarch64-apple-ios
+ ;;
+ armv7-apple-ios)
+ rustup target install armv7-apple-ios
+ ;;
+ armv7s-apple-ios)
+ rustup target install armv7s-apple-ios
+ ;;
+ i386-apple-ios)
+ rustup target install i386-apple-ios
+ ;;
+ x86_64-apple-ios)
+ rustup target install x86_64-apple-ios
+ ;;
+ esac
+
+ # This fetches latest stable release
+ local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
+ | cut -d/ -f3 \
+ | grep -E '^v[0.1.0-9.]+$' \
+ | $sort --version-sort \
+ | tail -n1)
+ curl -LSfs https://japaric.github.io/trust/install.sh | \
+ sh -s -- \
+ --force \
+ --git japaric/cross \
+ --tag $tag \
+ --target $target
+}
+
+main
diff --git a/third_party/rust/memmap/ci/script.sh b/third_party/rust/memmap/ci/script.sh
new file mode 100644
index 0000000000..3ccf556f61
--- /dev/null
+++ b/third_party/rust/memmap/ci/script.sh
@@ -0,0 +1,20 @@
+# This script takes care of testing your crate
+
+set -ex
+
+main() {
+ cross build --target $TARGET
+ cross build --target $TARGET --release
+
+ if [ ! -z $DISABLE_TESTS ]; then
+ return
+ fi
+
+ cross test --target $TARGET
+ cross test --target $TARGET --release
+}
+
+# we don't run the "test phase" when doing deploys
+if [ -z $TRAVIS_TAG ]; then
+ main
+fi
diff --git a/third_party/rust/memmap/examples/cat.rs b/third_party/rust/memmap/examples/cat.rs
new file mode 100644
index 0000000000..4745972ddb
--- /dev/null
+++ b/third_party/rust/memmap/examples/cat.rs
@@ -0,0 +1,23 @@
+extern crate memmap;
+
+use std::env;
+use std::fs::File;
+use std::io::{self, Write};
+
+use memmap::Mmap;
+
+/// Output a file's contents to stdout. The file path must be provided as the first process
+/// argument.
+fn main() {
+ let path = env::args()
+ .nth(1)
+ .expect("supply a single path as the program argument");
+
+ let file = File::open(path).expect("failed to open the file");
+
+ let mmap = unsafe { Mmap::map(&file).expect("failed to map the file") };
+
+ io::stdout()
+ .write_all(&mmap[..])
+ .expect("failed to output the file contents");
+}
diff --git a/third_party/rust/memmap/src/lib.rs b/third_party/rust/memmap/src/lib.rs
new file mode 100644
index 0000000000..5010c00581
--- /dev/null
+++ b/third_party/rust/memmap/src/lib.rs
@@ -0,0 +1,1008 @@
+//! A cross-platform Rust API for memory mapped buffers.
+
+#![doc(html_root_url = "https://docs.rs/memmap/0.7.0")]
+
+#[cfg(windows)]
+extern crate winapi;
+#[cfg(windows)]
+mod windows;
+#[cfg(windows)]
+use windows::MmapInner;
+
+#[cfg(unix)]
+mod unix;
+#[cfg(unix)]
+use unix::MmapInner;
+
+use std::fmt;
+use std::fs::File;
+use std::io::{Error, ErrorKind, Result};
+use std::ops::{Deref, DerefMut};
+use std::slice;
+use std::usize;
+
+/// A memory map builder, providing advanced options and flags for specifying memory map behavior.
+///
+/// `MmapOptions` can be used to create an anonymous memory map using `MmapOptions::map_anon`, or a
+/// file-backed memory map using one of `MmapOptions::map`, `MmapOptions::map_mut`,
+/// `MmapOptions::map_exec`, or `MmapOptions::map_copy`.
+#[derive(Clone, Debug, Default)]
+pub struct MmapOptions {
+ offset: u64,
+ len: Option<usize>,
+ stack: bool,
+}
+
+impl MmapOptions {
+ /// Creates a new set of options for configuring and creating a memory map.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use memmap::{MmapMut, MmapOptions};
+ /// # use std::io::Result;
+ ///
+ /// # fn main() -> Result<()> {
+ /// // Create a new memory map builder.
+ /// let mut mmap_options = MmapOptions::new();
+ ///
+ /// // Configure the memory map builder using option setters, then create
+ /// // a memory map using one of `mmap_options.map_anon`, `mmap_options.map`,
+ /// // `mmap_options.map_mut`, `mmap_options.map_exec`, or `mmap_options.map_copy`:
+ /// let mut mmap: MmapMut = mmap_options.len(36).map_anon()?;
+ ///
+ /// // Use the memory map:
+ /// mmap.copy_from_slice(b"...data to copy to the memory map...");
+ /// # let _ = mmap_options;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn new() -> MmapOptions {
+ MmapOptions::default()
+ }
+
+ /// Configures the memory map to start at byte `offset` from the beginning of the file.
+ ///
+ /// This option has no effect on anonymous memory maps.
+ ///
+ /// By default, the offset is 0.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use memmap::MmapOptions;
+ /// use std::fs::File;
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// let mmap = unsafe {
+ /// MmapOptions::new()
+ /// .offset(10)
+ /// .map(&File::open("README.md")?)?
+ /// };
+ /// assert_eq!(&b"A Rust library for cross-platform memory mapped IO."[..],
+ /// &mmap[..51]);
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn offset(&mut self, offset: u64) -> &mut Self {
+ self.offset = offset;
+ self
+ }
+
+ /// Configures the created memory mapped buffer to be `len` bytes long.
+ ///
+ /// This option is mandatory for anonymous memory maps.
+ ///
+ /// For file-backed memory maps, the length will default to the file length.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use memmap::MmapOptions;
+ /// use std::fs::File;
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// let mmap = unsafe {
+ /// MmapOptions::new()
+ /// .len(8)
+ /// .map(&File::open("README.md")?)?
+ /// };
+ /// assert_eq!(&b"# memmap"[..], &mmap[..]);
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn len(&mut self, len: usize) -> &mut Self {
+ self.len = Some(len);
+ self
+ }
+
+ /// Returns the configured length, or the length of the provided file.
+ fn get_len(&self, file: &File) -> Result<usize> {
+ self.len.map(Ok).unwrap_or_else(|| {
+ let len = file.metadata()?.len() - self.offset;
+ if len > (usize::MAX as u64) {
+ return Err(Error::new(
+ ErrorKind::InvalidData,
+ "memory map length overflows usize",
+ ));
+ }
+ Ok(len as usize)
+ })
+ }
+
+ /// Configures the anonymous memory map to be suitable for a process or thread stack.
+ ///
+ /// This option corresponds to the `MAP_STACK` flag on Linux.
+ ///
+ /// This option has no effect on file-backed memory maps.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use memmap::MmapOptions;
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// let stack = MmapOptions::new().stack().len(4096).map_anon();
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn stack(&mut self) -> &mut Self {
+ self.stack = true;
+ self
+ }
+
+ /// Creates a read-only memory map backed by a file.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails, which can happen for a
+ /// variety of reasons, such as when the file is not open with read permissions.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use memmap::MmapOptions;
+ /// use std::fs::File;
+ /// use std::io::Read;
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// let mut file = File::open("README.md")?;
+ ///
+ /// let mut contents = Vec::new();
+ /// file.read_to_end(&mut contents)?;
+ ///
+ /// let mmap = unsafe {
+ /// MmapOptions::new().map(&file)?
+ /// };
+ ///
+ /// assert_eq!(&contents[..], &mmap[..]);
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub unsafe fn map(&self, file: &File) -> Result<Mmap> {
+ MmapInner::map(self.get_len(file)?, file, self.offset).map(|inner| Mmap { inner: inner })
+ }
+
+ /// Creates a readable and executable memory map backed by a file.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails, which can happen for a
+ /// variety of reasons, such as when the file is not open with read permissions.
+ pub unsafe fn map_exec(&self, file: &File) -> Result<Mmap> {
+ MmapInner::map_exec(self.get_len(file)?, file, self.offset)
+ .map(|inner| Mmap { inner: inner })
+ }
+
+ /// Creates a writeable memory map backed by a file.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails, which can happen for a
+ /// variety of reasons, such as when the file is not open with read and write permissions.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # extern crate memmap;
+ /// # extern crate tempdir;
+ /// #
+ /// use std::fs::OpenOptions;
+ /// use std::path::PathBuf;
+ ///
+ /// use memmap::MmapOptions;
+ /// #
+ /// # fn main() -> std::io::Result<()> {
+ /// # let tempdir = tempdir::TempDir::new("mmap")?;
+ /// let path: PathBuf = /* path to file */
+ /// # tempdir.path().join("map_mut");
+ /// let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?;
+ /// file.set_len(13)?;
+ ///
+ /// let mut mmap = unsafe {
+ /// MmapOptions::new().map_mut(&file)?
+ /// };
+ ///
+ /// mmap.copy_from_slice(b"Hello, world!");
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub unsafe fn map_mut(&self, file: &File) -> Result<MmapMut> {
+ MmapInner::map_mut(self.get_len(file)?, file, self.offset)
+ .map(|inner| MmapMut { inner: inner })
+ }
+
+ /// Creates a copy-on-write memory map backed by a file.
+ ///
+ /// Data written to the memory map will not be visible by other processes,
+ /// and will not be carried through to the underlying file.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails, which can happen for a
+ /// variety of reasons, such as when the file is not open with writable permissions.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use memmap::MmapOptions;
+ /// use std::fs::File;
+ /// use std::io::Write;
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// let file = File::open("README.md")?;
+ /// let mut mmap = unsafe { MmapOptions::new().map_copy(&file)? };
+ /// (&mut mmap[..]).write_all(b"Hello, world!")?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub unsafe fn map_copy(&self, file: &File) -> Result<MmapMut> {
+ MmapInner::map_copy(self.get_len(file)?, file, self.offset)
+ .map(|inner| MmapMut { inner: inner })
+ }
+
+ /// Creates an anonymous memory map.
+ ///
+ /// Note: the memory map length must be configured to be greater than 0 before creating an
+ /// anonymous memory map using `MmapOptions::len()`.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails.
+ pub fn map_anon(&self) -> Result<MmapMut> {
+ MmapInner::map_anon(self.len.unwrap_or(0), self.stack).map(|inner| MmapMut { inner: inner })
+ }
+}
+
+/// An immutable memory mapped buffer.
+///
+/// A `Mmap` may be backed by a file, or it can be anonymous map, backed by volatile memory.
+///
+/// Use `MmapOptions` to configure and create a file-backed memory map. To create an immutable
+/// anonymous memory map, first create a mutable anonymous memory map using `MmapOptions`, and then
+/// make it immutable with `MmapMut::make_read_only`.
+///
+/// # Example
+///
+/// ```
+/// use memmap::MmapOptions;
+/// use std::io::Write;
+/// use std::fs::File;
+///
+/// # fn main() -> std::io::Result<()> {
+/// let file = File::open("README.md")?;
+/// let mmap = unsafe { MmapOptions::new().map(&file)? };
+/// assert_eq!(b"# memmap", &mmap[0..8]);
+/// # Ok(())
+/// # }
+/// ```
+///
+/// See `MmapMut` for the mutable version.
+pub struct Mmap {
+ inner: MmapInner,
+}
+
+impl Mmap {
+ /// Creates a read-only memory map backed by a file.
+ ///
+ /// This is equivalent to calling `MmapOptions::new().map(file)`.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails, which can happen for a
+ /// variety of reasons, such as when the file is not open with read permissions.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use std::fs::File;
+ /// use std::io::Read;
+ ///
+ /// use memmap::Mmap;
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// let mut file = File::open("README.md")?;
+ ///
+ /// let mut contents = Vec::new();
+ /// file.read_to_end(&mut contents)?;
+ ///
+ /// let mmap = unsafe { Mmap::map(&file)? };
+ ///
+ /// assert_eq!(&contents[..], &mmap[..]);
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub unsafe fn map(file: &File) -> Result<Mmap> {
+ MmapOptions::new().map(file)
+ }
+
+ /// Transition the memory map to be writable.
+ ///
+ /// If the memory map is file-backed, the file must have been opened with write permissions.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails, which can happen for a
+ /// variety of reasons, such as when the file is not open with writable permissions.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # extern crate memmap;
+ /// # extern crate tempdir;
+ /// #
+ /// use memmap::Mmap;
+ /// use std::ops::DerefMut;
+ /// use std::io::Write;
+ /// # use std::fs::OpenOptions;
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// # let tempdir = tempdir::TempDir::new("mmap")?;
+ /// let file = /* file opened with write permissions */
+ /// # OpenOptions::new()
+ /// # .read(true)
+ /// # .write(true)
+ /// # .create(true)
+ /// # .open(tempdir.path()
+ /// # .join("make_mut"))?;
+ /// # file.set_len(128)?;
+ /// let mmap = unsafe { Mmap::map(&file)? };
+ /// // ... use the read-only memory map ...
+ /// let mut mut_mmap = mmap.make_mut()?;
+ /// mut_mmap.deref_mut().write_all(b"hello, world!")?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn make_mut(mut self) -> Result<MmapMut> {
+ self.inner.make_mut()?;
+ Ok(MmapMut { inner: self.inner })
+ }
+}
+
+impl Deref for Mmap {
+ type Target = [u8];
+
+ #[inline]
+ fn deref(&self) -> &[u8] {
+ unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) }
+ }
+}
+
+impl AsRef<[u8]> for Mmap {
+ #[inline]
+ fn as_ref(&self) -> &[u8] {
+ self.deref()
+ }
+}
+
+impl fmt::Debug for Mmap {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("Mmap")
+ .field("ptr", &self.as_ptr())
+ .field("len", &self.len())
+ .finish()
+ }
+}
+
+/// A mutable memory mapped buffer.
+///
+/// A file-backed `MmapMut` buffer may be used to read from or write to a file. An anonymous
+/// `MmapMut` buffer may be used any place that an in-memory byte buffer is needed. Use
+/// `MmapOptions` for creating memory maps.
+///
+/// See `Mmap` for the immutable version.
+pub struct MmapMut {
+ inner: MmapInner,
+}
+
+impl MmapMut {
+ /// Creates a writeable memory map backed by a file.
+ ///
+ /// This is equivalent to calling `MmapOptions::new().map_mut(file)`.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails, which can happen for a
+ /// variety of reasons, such as when the file is not open with read and write permissions.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # extern crate memmap;
+ /// # extern crate tempdir;
+ /// #
+ /// use std::fs::OpenOptions;
+ /// use std::path::PathBuf;
+ ///
+ /// use memmap::MmapMut;
+ /// #
+ /// # fn main() -> std::io::Result<()> {
+ /// # let tempdir = tempdir::TempDir::new("mmap")?;
+ /// let path: PathBuf = /* path to file */
+ /// # tempdir.path().join("map_mut");
+ /// let file = OpenOptions::new()
+ /// .read(true)
+ /// .write(true)
+ /// .create(true)
+ /// .open(&path)?;
+ /// file.set_len(13)?;
+ ///
+ /// let mut mmap = unsafe { MmapMut::map_mut(&file)? };
+ ///
+ /// mmap.copy_from_slice(b"Hello, world!");
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub unsafe fn map_mut(file: &File) -> Result<MmapMut> {
+ MmapOptions::new().map_mut(file)
+ }
+
+ /// Creates an anonymous memory map.
+ ///
+ /// This is equivalent to calling `MmapOptions::new().len(length).map_anon()`.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails.
+ pub fn map_anon(length: usize) -> Result<MmapMut> {
+ MmapOptions::new().len(length).map_anon()
+ }
+
+ /// Flushes outstanding memory map modifications to disk.
+ ///
+ /// When this method returns with a non-error result, all outstanding changes to a file-backed
+ /// memory map are guaranteed to be durably stored. The file's metadata (including last
+ /// modification timestamp) may not be updated.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # extern crate memmap;
+ /// # extern crate tempdir;
+ /// #
+ /// use std::fs::OpenOptions;
+ /// use std::io::Write;
+ /// use std::path::PathBuf;
+ ///
+ /// use memmap::MmapMut;
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// # let tempdir = tempdir::TempDir::new("mmap")?;
+ /// let path: PathBuf = /* path to file */
+ /// # tempdir.path().join("flush");
+ /// let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?;
+ /// file.set_len(128)?;
+ ///
+ /// let mut mmap = unsafe { MmapMut::map_mut(&file)? };
+ ///
+ /// (&mut mmap[..]).write_all(b"Hello, world!")?;
+ /// mmap.flush()?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn flush(&self) -> Result<()> {
+ let len = self.len();
+ self.inner.flush(0, len)
+ }
+
+ /// Asynchronously flushes outstanding memory map modifications to disk.
+ ///
+ /// This method initiates flushing modified pages to durable storage, but it will not wait for
+ /// the operation to complete before returning. The file's metadata (including last
+ /// modification timestamp) may not be updated.
+ pub fn flush_async(&self) -> Result<()> {
+ let len = self.len();
+ self.inner.flush_async(0, len)
+ }
+
+ /// Flushes outstanding memory map modifications in the range to disk.
+ ///
+ /// The offset and length must be in the bounds of the memory map.
+ ///
+ /// When this method returns with a non-error result, all outstanding changes to a file-backed
+ /// memory in the range are guaranteed to be durable stored. The file's metadata (including
+ /// last modification timestamp) may not be updated. It is not guaranteed the only the changes
+ /// in the specified range are flushed; other outstanding changes to the memory map may be
+ /// flushed as well.
+ pub fn flush_range(&self, offset: usize, len: usize) -> Result<()> {
+ self.inner.flush(offset, len)
+ }
+
+ /// Asynchronously flushes outstanding memory map modifications in the range to disk.
+ ///
+ /// The offset and length must be in the bounds of the memory map.
+ ///
+ /// This method initiates flushing modified pages to durable storage, but it will not wait for
+ /// the operation to complete before returning. The file's metadata (including last
+ /// modification timestamp) may not be updated. It is not guaranteed that the only changes
+ /// flushed are those in the specified range; other outstanding changes to the memory map may
+ /// be flushed as well.
+ pub fn flush_async_range(&self, offset: usize, len: usize) -> Result<()> {
+ self.inner.flush_async(offset, len)
+ }
+
+ /// Returns an immutable version of this memory mapped buffer.
+ ///
+ /// If the memory map is file-backed, the file must have been opened with read permissions.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails, which can happen for a
+ /// variety of reasons, such as when the file has not been opened with read permissions.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # extern crate memmap;
+ /// #
+ /// use std::io::Write;
+ /// use std::path::PathBuf;
+ ///
+ /// use memmap::{Mmap, MmapMut};
+ ///
+ /// # fn main() -> std::io::Result<()> {
+ /// let mut mmap = MmapMut::map_anon(128)?;
+ ///
+ /// (&mut mmap[..]).write(b"Hello, world!")?;
+ ///
+ /// let mmap: Mmap = mmap.make_read_only()?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn make_read_only(mut self) -> Result<Mmap> {
+ self.inner.make_read_only()?;
+ Ok(Mmap { inner: self.inner })
+ }
+
+ /// Transition the memory map to be readable and executable.
+ ///
+ /// If the memory map is file-backed, the file must have been opened with execute permissions.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails, which can happen for a
+ /// variety of reasons, such as when the file has not been opened with execute permissions.
+ pub fn make_exec(mut self) -> Result<Mmap> {
+ self.inner.make_exec()?;
+ Ok(Mmap { inner: self.inner })
+ }
+}
+
+impl Deref for MmapMut {
+ type Target = [u8];
+
+ #[inline]
+ fn deref(&self) -> &[u8] {
+ unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) }
+ }
+}
+
+impl DerefMut for MmapMut {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe { slice::from_raw_parts_mut(self.inner.mut_ptr(), self.inner.len()) }
+ }
+}
+
+impl AsRef<[u8]> for MmapMut {
+ #[inline]
+ fn as_ref(&self) -> &[u8] {
+ self.deref()
+ }
+}
+
+impl AsMut<[u8]> for MmapMut {
+ #[inline]
+ fn as_mut(&mut self) -> &mut [u8] {
+ self.deref_mut()
+ }
+}
+
+impl fmt::Debug for MmapMut {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("MmapMut")
+ .field("ptr", &self.as_ptr())
+ .field("len", &self.len())
+ .finish()
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ extern crate tempdir;
+ #[cfg(windows)]
+ extern crate winapi;
+
+ use std::fs::OpenOptions;
+ use std::io::{Read, Write};
+ #[cfg(windows)]
+ use std::os::windows::fs::OpenOptionsExt;
+ use std::sync::Arc;
+ use std::thread;
+
+ #[cfg(windows)]
+ use winapi::um::winnt::GENERIC_ALL;
+
+ use super::{Mmap, MmapMut, MmapOptions};
+
+ #[test]
+ fn map_file() {
+ let expected_len = 128;
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let file = OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+
+ file.set_len(expected_len as u64).unwrap();
+
+ let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
+ let len = mmap.len();
+ assert_eq!(expected_len, len);
+
+ let zeros = vec![0; len];
+ let incr: Vec<u8> = (0..len as u8).collect();
+
+ // check that the mmap is empty
+ assert_eq!(&zeros[..], &mmap[..]);
+
+ // write values into the mmap
+ (&mut mmap[..]).write_all(&incr[..]).unwrap();
+
+ // read values back
+ assert_eq!(&incr[..], &mmap[..]);
+ }
+
+ /// Checks that a 0-length file will not be mapped.
+ #[test]
+ fn map_empty_file() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let file = OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+ let mmap = unsafe { Mmap::map(&file) };
+ assert!(mmap.is_err());
+ }
+
+ #[test]
+ fn map_anon() {
+ let expected_len = 128;
+ let mut mmap = MmapMut::map_anon(expected_len).unwrap();
+ let len = mmap.len();
+ assert_eq!(expected_len, len);
+
+ let zeros = vec![0; len];
+ let incr: Vec<u8> = (0..len as u8).collect();
+
+ // check that the mmap is empty
+ assert_eq!(&zeros[..], &mmap[..]);
+
+ // write values into the mmap
+ (&mut mmap[..]).write_all(&incr[..]).unwrap();
+
+ // read values back
+ assert_eq!(&incr[..], &mmap[..]);
+ }
+
+ #[test]
+ fn map_anon_zero_len() {
+ assert!(MmapOptions::new().map_anon().is_err())
+ }
+
+ #[test]
+ fn file_write() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let mut file = OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+ file.set_len(128).unwrap();
+
+ let write = b"abc123";
+ let mut read = [0u8; 6];
+
+ let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
+ (&mut mmap[..]).write_all(write).unwrap();
+ mmap.flush().unwrap();
+
+ file.read(&mut read).unwrap();
+ assert_eq!(write, &read);
+ }
+
+ #[test]
+ fn flush_range() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let file = OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+ file.set_len(128).unwrap();
+ let write = b"abc123";
+
+ let mut mmap = unsafe {
+ MmapOptions::new()
+ .offset(2)
+ .len(write.len())
+ .map_mut(&file)
+ .unwrap()
+ };
+ (&mut mmap[..]).write_all(write).unwrap();
+ mmap.flush_range(0, write.len()).unwrap();
+ }
+
+ #[test]
+ fn map_copy() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let mut file = OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+ file.set_len(128).unwrap();
+
+ let nulls = b"\0\0\0\0\0\0";
+ let write = b"abc123";
+ let mut read = [0u8; 6];
+
+ let mut mmap = unsafe { MmapOptions::new().map_copy(&file).unwrap() };
+
+ (&mut mmap[..]).write(write).unwrap();
+ mmap.flush().unwrap();
+
+ // The mmap contains the write
+ (&mmap[..]).read(&mut read).unwrap();
+ assert_eq!(write, &read);
+
+ // The file does not contain the write
+ file.read(&mut read).unwrap();
+ assert_eq!(nulls, &read);
+
+ // another mmap does not contain the write
+ let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
+ (&mmap2[..]).read(&mut read).unwrap();
+ assert_eq!(nulls, &read);
+ }
+
+ #[test]
+ fn map_offset() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let file = OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .unwrap();
+
+ let offset = u32::max_value() as u64 + 2;
+ let len = 5432;
+ file.set_len(offset + len as u64).unwrap();
+
+ // Check inferred length mmap.
+ let mmap = unsafe { MmapOptions::new().offset(offset).map_mut(&file).unwrap() };
+ assert_eq!(len, mmap.len());
+
+ // Check explicit length mmap.
+ let mut mmap = unsafe {
+ MmapOptions::new()
+ .offset(offset)
+ .len(len)
+ .map_mut(&file)
+ .unwrap()
+ };
+ assert_eq!(len, mmap.len());
+
+ let zeros = vec![0; len];
+ let incr: Vec<_> = (0..len).map(|i| i as u8).collect();
+
+ // check that the mmap is empty
+ assert_eq!(&zeros[..], &mmap[..]);
+
+ // write values into the mmap
+ (&mut mmap[..]).write_all(&incr[..]).unwrap();
+
+ // read values back
+ assert_eq!(&incr[..], &mmap[..]);
+ }
+
+ #[test]
+ fn index() {
+ let mut mmap = MmapMut::map_anon(128).unwrap();
+ mmap[0] = 42;
+ assert_eq!(42, mmap[0]);
+ }
+
+ #[test]
+ fn sync_send() {
+ let mmap = Arc::new(MmapMut::map_anon(129).unwrap());
+ thread::spawn(move || {
+ &mmap[..];
+ });
+ }
+
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ fn jit_x86(mut mmap: MmapMut) {
+ use std::mem;
+ mmap[0] = 0xB8; // mov eax, 0xAB
+ mmap[1] = 0xAB;
+ mmap[2] = 0x00;
+ mmap[3] = 0x00;
+ mmap[4] = 0x00;
+ mmap[5] = 0xC3; // ret
+
+ let mmap = mmap.make_exec().expect("make_exec");
+
+ let jitfn: extern "C" fn() -> u8 = unsafe { mem::transmute(mmap.as_ptr()) };
+ assert_eq!(jitfn(), 0xab);
+ }
+
+ #[test]
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ fn jit_x86_anon() {
+ jit_x86(MmapMut::map_anon(4096).unwrap());
+ }
+
+ #[test]
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ fn jit_x86_file() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let mut options = OpenOptions::new();
+ #[cfg(windows)]
+ options.access_mode(GENERIC_ALL);
+
+ let file = options
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&tempdir.path().join("jit_x86"))
+ .expect("open");
+
+ file.set_len(4096).expect("set_len");
+ jit_x86(unsafe { MmapMut::map_mut(&file).expect("map_mut") });
+ }
+
+ #[test]
+ fn mprotect_file() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let mut options = OpenOptions::new();
+ #[cfg(windows)]
+ options.access_mode(GENERIC_ALL);
+
+ let mut file = options
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .expect("open");
+ file.set_len(256 as u64).expect("set_len");
+
+ let mmap = unsafe { MmapMut::map_mut(&file).expect("map_mut") };
+
+ let mmap = mmap.make_read_only().expect("make_read_only");
+ let mut mmap = mmap.make_mut().expect("make_mut");
+
+ let write = b"abc123";
+ let mut read = [0u8; 6];
+
+ (&mut mmap[..]).write(write).unwrap();
+ mmap.flush().unwrap();
+
+ // The mmap contains the write
+ (&mmap[..]).read(&mut read).unwrap();
+ assert_eq!(write, &read);
+
+ // The file should contain the write
+ file.read(&mut read).unwrap();
+ assert_eq!(write, &read);
+
+ // another mmap should contain the write
+ let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
+ (&mmap2[..]).read(&mut read).unwrap();
+ assert_eq!(write, &read);
+
+ let mmap = mmap.make_exec().expect("make_exec");
+
+ drop(mmap);
+ }
+
+ #[test]
+ fn mprotect_copy() {
+ let tempdir = tempdir::TempDir::new("mmap").unwrap();
+ let path = tempdir.path().join("mmap");
+
+ let mut options = OpenOptions::new();
+ #[cfg(windows)]
+ options.access_mode(GENERIC_ALL);
+
+ let mut file = options
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(&path)
+ .expect("open");
+ file.set_len(256 as u64).expect("set_len");
+
+ let mmap = unsafe { MmapOptions::new().map_copy(&file).expect("map_mut") };
+
+ let mmap = mmap.make_read_only().expect("make_read_only");
+ let mut mmap = mmap.make_mut().expect("make_mut");
+
+ let nulls = b"\0\0\0\0\0\0";
+ let write = b"abc123";
+ let mut read = [0u8; 6];
+
+ (&mut mmap[..]).write(write).unwrap();
+ mmap.flush().unwrap();
+
+ // The mmap contains the write
+ (&mmap[..]).read(&mut read).unwrap();
+ assert_eq!(write, &read);
+
+ // The file does not contain the write
+ file.read(&mut read).unwrap();
+ assert_eq!(nulls, &read);
+
+ // another mmap does not contain the write
+ let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
+ (&mmap2[..]).read(&mut read).unwrap();
+ assert_eq!(nulls, &read);
+
+ let mmap = mmap.make_exec().expect("make_exec");
+
+ drop(mmap);
+ }
+
+ #[test]
+ fn mprotect_anon() {
+ let mmap = MmapMut::map_anon(256).expect("map_mut");
+
+ let mmap = mmap.make_read_only().expect("make_read_only");
+ let mmap = mmap.make_mut().expect("make_mut");
+ let mmap = mmap.make_exec().expect("make_exec");
+ drop(mmap);
+ }
+}
diff --git a/third_party/rust/memmap/src/unix.rs b/third_party/rust/memmap/src/unix.rs
new file mode 100644
index 0000000000..4838e7e4f7
--- /dev/null
+++ b/third_party/rust/memmap/src/unix.rs
@@ -0,0 +1,214 @@
+extern crate libc;
+
+use std::fs::File;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::{io, ptr};
+
+#[cfg(any(
+ all(target_os = "linux", not(target_arch = "mips")),
+ target_os = "freebsd",
+ target_os = "android"
+))]
+const MAP_STACK: libc::c_int = libc::MAP_STACK;
+
+#[cfg(not(any(
+ all(target_os = "linux", not(target_arch = "mips")),
+ target_os = "freebsd",
+ target_os = "android"
+)))]
+const MAP_STACK: libc::c_int = 0;
+
+pub struct MmapInner {
+ ptr: *mut libc::c_void,
+ len: usize,
+}
+
+impl MmapInner {
+ /// Creates a new `MmapInner`.
+ ///
+ /// This is a thin wrapper around the `mmap` sytem call.
+ fn new(
+ len: usize,
+ prot: libc::c_int,
+ flags: libc::c_int,
+ file: RawFd,
+ offset: u64,
+ ) -> io::Result<MmapInner> {
+ let alignment = offset % page_size() as u64;
+ let aligned_offset = offset - alignment;
+ let aligned_len = len + alignment as usize;
+ if aligned_len == 0 {
+ // Normally the OS would catch this, but it segfaults under QEMU.
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "memory map must have a non-zero length",
+ ));
+ }
+
+ unsafe {
+ let ptr = libc::mmap(
+ ptr::null_mut(),
+ aligned_len as libc::size_t,
+ prot,
+ flags,
+ file,
+ aligned_offset as libc::off_t,
+ );
+
+ if ptr == libc::MAP_FAILED {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(MmapInner {
+ ptr: ptr.offset(alignment as isize),
+ len: len,
+ })
+ }
+ }
+ }
+
+ pub fn map(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
+ MmapInner::new(
+ len,
+ libc::PROT_READ,
+ libc::MAP_SHARED,
+ file.as_raw_fd(),
+ offset,
+ )
+ }
+
+ pub fn map_exec(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
+ MmapInner::new(
+ len,
+ libc::PROT_READ | libc::PROT_EXEC,
+ libc::MAP_SHARED,
+ file.as_raw_fd(),
+ offset,
+ )
+ }
+
+ pub fn map_mut(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
+ MmapInner::new(
+ len,
+ libc::PROT_READ | libc::PROT_WRITE,
+ libc::MAP_SHARED,
+ file.as_raw_fd(),
+ offset,
+ )
+ }
+
+ pub fn map_copy(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
+ MmapInner::new(
+ len,
+ libc::PROT_READ | libc::PROT_WRITE,
+ libc::MAP_PRIVATE,
+ file.as_raw_fd(),
+ offset,
+ )
+ }
+
+ /// Open an anonymous memory map.
+ pub fn map_anon(len: usize, stack: bool) -> io::Result<MmapInner> {
+ let stack = if stack { MAP_STACK } else { 0 };
+ MmapInner::new(
+ len,
+ libc::PROT_READ | libc::PROT_WRITE,
+ libc::MAP_SHARED | libc::MAP_ANON | stack,
+ -1,
+ 0,
+ )
+ }
+
+ pub fn flush(&self, offset: usize, len: usize) -> io::Result<()> {
+ let alignment = (self.ptr as usize + offset) % page_size();
+ let offset = offset as isize - alignment as isize;
+ let len = len + alignment;
+ let result =
+ unsafe { libc::msync(self.ptr.offset(offset), len as libc::size_t, libc::MS_SYNC) };
+ if result == 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+
+ pub fn flush_async(&self, offset: usize, len: usize) -> io::Result<()> {
+ let alignment = offset % page_size();
+ let aligned_offset = offset - alignment;
+ let aligned_len = len + alignment;
+ let result = unsafe {
+ libc::msync(
+ self.ptr.offset(aligned_offset as isize),
+ aligned_len as libc::size_t,
+ libc::MS_ASYNC,
+ )
+ };
+ if result == 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+
+ fn mprotect(&mut self, prot: libc::c_int) -> io::Result<()> {
+ unsafe {
+ let alignment = self.ptr as usize % page_size();
+ let ptr = self.ptr.offset(-(alignment as isize));
+ let len = self.len + alignment;
+ if libc::mprotect(ptr, len, prot) == 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+
+ pub fn make_read_only(&mut self) -> io::Result<()> {
+ self.mprotect(libc::PROT_READ)
+ }
+
+ pub fn make_exec(&mut self) -> io::Result<()> {
+ self.mprotect(libc::PROT_READ | libc::PROT_EXEC)
+ }
+
+ pub fn make_mut(&mut self) -> io::Result<()> {
+ self.mprotect(libc::PROT_READ | libc::PROT_WRITE)
+ }
+
+ #[inline]
+ pub fn ptr(&self) -> *const u8 {
+ self.ptr as *const u8
+ }
+
+ #[inline]
+ pub fn mut_ptr(&mut self) -> *mut u8 {
+ self.ptr as *mut u8
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.len
+ }
+}
+
+impl Drop for MmapInner {
+ fn drop(&mut self) {
+ let alignment = self.ptr as usize % page_size();
+ unsafe {
+ assert!(
+ libc::munmap(
+ self.ptr.offset(-(alignment as isize)),
+ (self.len + alignment) as libc::size_t
+ ) == 0,
+ "unable to unmap mmap: {}",
+ io::Error::last_os_error()
+ );
+ }
+ }
+}
+
+unsafe impl Sync for MmapInner {}
+unsafe impl Send for MmapInner {}
+
+fn page_size() -> usize {
+ unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
+}
diff --git a/third_party/rust/memmap/src/windows.rs b/third_party/rust/memmap/src/windows.rs
new file mode 100644
index 0000000000..d8aa99d255
--- /dev/null
+++ b/third_party/rust/memmap/src/windows.rs
@@ -0,0 +1,300 @@
+use std::fs::File;
+use std::os::raw::c_void;
+use std::os::windows::io::{AsRawHandle, RawHandle};
+use std::{io, mem, ptr};
+
+use winapi::shared::basetsd::SIZE_T;
+use winapi::shared::minwindef::DWORD;
+use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
+use winapi::um::memoryapi::{
+ CreateFileMappingW, FlushViewOfFile, MapViewOfFile, UnmapViewOfFile, VirtualProtect,
+ FILE_MAP_ALL_ACCESS, FILE_MAP_COPY, FILE_MAP_EXECUTE, FILE_MAP_READ, FILE_MAP_WRITE,
+};
+use winapi::um::sysinfoapi::GetSystemInfo;
+use winapi::um::winnt::{
+ PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY, PAGE_READONLY,
+ PAGE_READWRITE, PAGE_WRITECOPY,
+};
+
+pub struct MmapInner {
+ file: Option<File>,
+ ptr: *mut c_void,
+ len: usize,
+ copy: bool,
+}
+
+impl MmapInner {
+ /// Creates a new `MmapInner`.
+ ///
+ /// This is a thin wrapper around the `CreateFileMappingW` and `MapViewOfFile` system calls.
+ pub fn new(
+ file: &File,
+ protect: DWORD,
+ access: DWORD,
+ offset: u64,
+ len: usize,
+ copy: bool,
+ ) -> io::Result<MmapInner> {
+ let alignment = offset % allocation_granularity() as u64;
+ let aligned_offset = offset - alignment as u64;
+ let aligned_len = len + alignment as usize;
+
+ unsafe {
+ let handle = CreateFileMappingW(
+ file.as_raw_handle(),
+ ptr::null_mut(),
+ protect,
+ 0,
+ 0,
+ ptr::null(),
+ );
+ if handle == ptr::null_mut() {
+ return Err(io::Error::last_os_error());
+ }
+
+ let ptr = MapViewOfFile(
+ handle,
+ access,
+ (aligned_offset >> 16 >> 16) as DWORD,
+ (aligned_offset & 0xffffffff) as DWORD,
+ aligned_len as SIZE_T,
+ );
+ CloseHandle(handle);
+
+ if ptr == ptr::null_mut() {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(MmapInner {
+ file: Some(file.try_clone()?),
+ ptr: ptr.offset(alignment as isize),
+ len: len as usize,
+ copy: copy,
+ })
+ }
+ }
+ }
+
+ pub fn map(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
+ let write = protection_supported(file.as_raw_handle(), PAGE_READWRITE);
+ let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READ);
+ let mut access = FILE_MAP_READ;
+ let protection = match (write, exec) {
+ (true, true) => {
+ access |= FILE_MAP_WRITE | FILE_MAP_EXECUTE;
+ PAGE_EXECUTE_READWRITE
+ }
+ (true, false) => {
+ access |= FILE_MAP_WRITE;
+ PAGE_READWRITE
+ }
+ (false, true) => {
+ access |= FILE_MAP_EXECUTE;
+ PAGE_EXECUTE_READ
+ }
+ (false, false) => PAGE_READONLY,
+ };
+
+ let mut inner = MmapInner::new(file, protection, access, offset, len, false)?;
+ if write || exec {
+ inner.make_read_only()?;
+ }
+ Ok(inner)
+ }
+
+ pub fn map_exec(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
+ let write = protection_supported(file.as_raw_handle(), PAGE_READWRITE);
+ let mut access = FILE_MAP_READ | FILE_MAP_EXECUTE;
+ let protection = if write {
+ access |= FILE_MAP_WRITE;
+ PAGE_EXECUTE_READWRITE
+ } else {
+ PAGE_EXECUTE_READ
+ };
+
+ let mut inner = MmapInner::new(file, protection, access, offset, len, false)?;
+ if write {
+ inner.make_exec()?;
+ }
+ Ok(inner)
+ }
+
+ pub fn map_mut(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
+ let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READ);
+ let mut access = FILE_MAP_READ | FILE_MAP_WRITE;
+ let protection = if exec {
+ access |= FILE_MAP_EXECUTE;
+ PAGE_EXECUTE_READWRITE
+ } else {
+ PAGE_READWRITE
+ };
+
+ let mut inner = MmapInner::new(file, protection, access, offset, len, false)?;
+ if exec {
+ inner.make_mut()?;
+ }
+ Ok(inner)
+ }
+
+ pub fn map_copy(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
+ let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READWRITE);
+ let mut access = FILE_MAP_COPY;
+ let protection = if exec {
+ access |= FILE_MAP_EXECUTE;
+ PAGE_EXECUTE_WRITECOPY
+ } else {
+ PAGE_WRITECOPY
+ };
+
+ let mut inner = MmapInner::new(file, protection, access, offset, len, true)?;
+ if exec {
+ inner.make_mut()?;
+ }
+ Ok(inner)
+ }
+
+ pub fn map_anon(len: usize, _stack: bool) -> io::Result<MmapInner> {
+ unsafe {
+ // Create a mapping and view with maximum access permissions, then use `VirtualProtect`
+ // to set the actual `Protection`. This way, we can set more permissive protection later
+ // on.
+ // Also see https://msdn.microsoft.com/en-us/library/windows/desktop/aa366537.aspx
+
+ let handle = CreateFileMappingW(
+ INVALID_HANDLE_VALUE,
+ ptr::null_mut(),
+ PAGE_EXECUTE_READWRITE,
+ (len >> 16 >> 16) as DWORD,
+ (len & 0xffffffff) as DWORD,
+ ptr::null(),
+ );
+ if handle == ptr::null_mut() {
+ return Err(io::Error::last_os_error());
+ }
+ let access = FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE;
+ let ptr = MapViewOfFile(handle, access, 0, 0, len as SIZE_T);
+ CloseHandle(handle);
+
+ if ptr == ptr::null_mut() {
+ return Err(io::Error::last_os_error());
+ }
+
+ let mut old = 0;
+ let result = VirtualProtect(ptr, len as SIZE_T, PAGE_READWRITE, &mut old);
+ if result != 0 {
+ Ok(MmapInner {
+ file: None,
+ ptr: ptr,
+ len: len as usize,
+ copy: false,
+ })
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+
+ pub fn flush(&self, offset: usize, len: usize) -> io::Result<()> {
+ self.flush_async(offset, len)?;
+ if let Some(ref file) = self.file {
+ file.sync_data()?;
+ }
+ Ok(())
+ }
+
+ pub fn flush_async(&self, offset: usize, len: usize) -> io::Result<()> {
+ let result = unsafe { FlushViewOfFile(self.ptr.offset(offset as isize), len as SIZE_T) };
+ if result != 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+
+ fn virtual_protect(&mut self, protect: DWORD) -> io::Result<()> {
+ unsafe {
+ let alignment = self.ptr as usize % allocation_granularity();
+ let ptr = self.ptr.offset(-(alignment as isize));
+ let aligned_len = self.len as SIZE_T + alignment as SIZE_T;
+
+ let mut old = 0;
+ let result = VirtualProtect(ptr, aligned_len, protect, &mut old);
+
+ if result != 0 {
+ Ok(())
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+
+ pub fn make_read_only(&mut self) -> io::Result<()> {
+ self.virtual_protect(PAGE_READONLY)
+ }
+
+ pub fn make_exec(&mut self) -> io::Result<()> {
+ if self.copy {
+ self.virtual_protect(PAGE_EXECUTE_WRITECOPY)
+ } else {
+ self.virtual_protect(PAGE_EXECUTE_READ)
+ }
+ }
+
+ pub fn make_mut(&mut self) -> io::Result<()> {
+ if self.copy {
+ self.virtual_protect(PAGE_WRITECOPY)
+ } else {
+ self.virtual_protect(PAGE_READWRITE)
+ }
+ }
+
+ #[inline]
+ pub fn ptr(&self) -> *const u8 {
+ self.ptr as *const u8
+ }
+
+ #[inline]
+ pub fn mut_ptr(&mut self) -> *mut u8 {
+ self.ptr as *mut u8
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.len
+ }
+}
+
+impl Drop for MmapInner {
+ fn drop(&mut self) {
+ let alignment = self.ptr as usize % allocation_granularity();
+ unsafe {
+ let ptr = self.ptr.offset(-(alignment as isize));
+ assert!(
+ UnmapViewOfFile(ptr) != 0,
+ "unable to unmap mmap: {}",
+ io::Error::last_os_error()
+ );
+ }
+ }
+}
+
+unsafe impl Sync for MmapInner {}
+unsafe impl Send for MmapInner {}
+
+fn protection_supported(handle: RawHandle, protection: DWORD) -> bool {
+ unsafe {
+ let handle = CreateFileMappingW(handle, ptr::null_mut(), protection, 0, 0, ptr::null());
+ if handle == ptr::null_mut() {
+ return false;
+ }
+ CloseHandle(handle);
+ true
+ }
+}
+
+fn allocation_granularity() -> usize {
+ unsafe {
+ let mut info = mem::zeroed();
+ GetSystemInfo(&mut info);
+ return info.dwAllocationGranularity as usize;
+ }
+}