Merge remote-tracking branch 'origin/upstream' am: 3fba44c118

Original change: undetermined

Change-Id: I45f2a1180ecd2ffe43fde9e4a7c1953aaf2b4014
Signed-off-by: Automerger Merge Worker <[email protected]>
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..0b3ddcd
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,78 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file as changes will be overridden on upgrade.
+
+package {
+    default_applicable_licenses: ["external_rust_crates_memmap2_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change included anything that looked like it might be a license
+// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
+//
+// Please consider removing redundant or irrelevant files from 'license_text:'.
+// See: http://go/android-license-faq
+license {
+    name: "external_rust_crates_memmap2_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-MIT",
+    ],
+    license_text: [
+        "LICENSE",
+        "LICENSE-APACHE",
+        "LICENSE-MIT",
+    ],
+}
+
+rust_library {
+    name: "libmemmap2",
+    host_supported: true,
+    crate_name: "memmap2",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.8.0",
+    srcs: ["src/lib.rs"],
+    edition: "2021",
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    rustlibs: [
+        "liblibc",
+    ],
+    product_available: true,
+    vendor_available: true,
+    min_sdk_version: "29",
+}
+
+rust_test {
+    name: "memmap2_test_src_lib",
+    host_supported: true,
+    crate_name: "memmap2",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.8.0",
+    srcs: ["src/lib.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    test_options: {
+        unit_test: true,
+    },
+    edition: "2021",
+    rustlibs: [
+        "liblibc",
+        "libtempfile",
+    ],
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..acd70dd
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,201 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/)
+and this project adheres to [Semantic Versioning](http://semver.org/).
+
+## [Unreleased]
+
+## [0.8.0] - 2023-09-25
+### Changed
+- The `Advice` type is a struct and not an enum now.
+  [@adamreichold](https://github.com/adamreichold)
+
+### Fixed
+- Some of the `Advise` variants were unsound and now require `unsafe` to be constructed.
+  [@adamreichold](https://github.com/adamreichold)
+
+## [0.7.1] - 2023-06-24
+### Fixed
+- Mapping beyond 4GB offset on 32 bit glibc. Linux-only.
+  [@lvella](https://github.com/lvella)
+
+## [0.7.0] - 2023-06-08
+### Added
+- `Mmap::remap`, `MmapMut::remap` and `MmapRaw::remap`. Linux-only.
+  [@Phantomical](https://github.com/Phantomical)
+- `Advice::PopulateRead` and `Advice::PopulateWrite`. Linux-only.
+  [@Jesse-Bakker](https://github.com/Jesse-Bakker)
+
+### Changed
+- libc crate >= 0.2.143 is required now.
+
+## [0.6.2] - 2023-05-24
+### Fixed
+- Alignment for empty files on Windows.
+  [@timvisee](https://github.com/timvisee)
+
+## [0.6.1] - 2023-05-10
+### Added
+- Add `MmapOptions::map_raw_read_only` to avoid intermediate invalid `Mmap` instances.
+  [@adamreichold](https://github.com/adamreichold)
+
+## [0.6.0] - 2023-05-09
+### Changed
+- `lock()` and `unlock` methods require `&self` and not `&mut self` now.
+  [@timvisee](https://github.com/timvisee)
+
+## [0.5.10] - 2023-02-22
+### Added
+- `MmapOptions::map_anon` accounts for `populate` on Linux now.
+  [@jsgf](https://github.com/jsgf)
+
+## [0.5.9] - 2023-02-17
+### Added
+- `From<Mmap> for MmapRaw` and `From<MmapMut> for MmapRaw`.
+  [@swlynch99](https://github.com/swlynch99)
+- `Mmap::advise_range`, `MmapMut::advise_range`, `MmapRaw::advise_range`.
+  [@ho-229](https://github.com/ho-229)
+
+## [0.5.8] - 2022-11-09
+### Added
+- `MmapRaw::advise`, `MmapRaw::lock` and `MmapRaw::unlock`.
+  [@diwic](https://github.com/diwic)
+- Improve `MmapMut::make_exec` documentation.
+
+## [0.5.7] - 2022-08-15
+### Changed
+- Simplify file size retrieving code.
+  [@saethlin](https://github.com/saethlin)
+
+## [0.5.6] - 2022-08-11
+### Added
+- Memory locking and unlocking. See `Mmap::lock`, `Mmap::unlock`,
+  `MmapMut::lock` and `MmapMut::unlock`.
+  [@vmx](https://github.com/vmx)
+
+## [0.5.5] - 2022-07-09
+### Fixed
+- Limit mapping length to `isize::MAX` to prevent undefined behavior
+  on calling `std::slice::from_raw_parts`. Technically affects only 32-bit systems.
+  [@adamreichold](https://github.com/adamreichold)
+
+## [0.5.4] - 2022-06-04
+### Added
+- Add madvice operations specific to Darwin. [@turbocool3r](https://github.com/turbocool3r)
+- Implement common traits for the `Advice` enum. [@nyurik](https://github.com/nyurik)
+
+### Changed
+- Make stub implementation Infallible. [@coolreader18](https://github.com/coolreader18)
+- Use `tempfile` crate instead of `tempdir` in tests.
+  [@alexanderkjall](https://github.com/alexanderkjall)
+
+## [0.5.3] - 2022-02-10
+### Added
+- `Mmap::advise` and `MmapMut::advise`. [@nyurik](https://github.com/nyurik)
+
+## [0.5.2] - 2022-01-10
+### Added
+- `flush`, `flush_async`, `flush_range` and `flush_async_range` to `MmapRaw` matching
+  the corresponding methods on `MmapMut`.
+  [@cberner](https://github.com/cberner)
+
+## [0.5.1] - 2022-01-09
+### Fixed
+- Explicitly call `fstat64` on Linux, emscripten and l4re targets.
+  [@adamreichold](https://github.com/adamreichold)
+
+## [0.5.0] - 2021-09-19
+### Added
+- `MmapOptions` accepts any type that supports `RawHandle`/`RawFd` returning now.
+  This allows using `memmap2` not only with Rust std types, but also with
+  [async-std](https://github.com/async-rs/async-std) one.
+  [@adamreichold](https://github.com/adamreichold)
+- (unix) Memoize page size to avoid repeatedly calling into sysconf machinery.
+  [@adamreichold](https://github.com/adamreichold)
+
+### Changed
+- (win) Use `std::os::windows::io::AsRawHandle` directly, without relying on `std::fs::File`.
+  [@adamreichold](https://github.com/adamreichold)
+- Do not panic when failing to release resources in Drop impls.
+  [@adamreichold](https://github.com/adamreichold)
+
+## [0.4.0] - 2021-09-16
+### Added
+- Optional [`StableDeref`](https://github.com/storyyeller/stable_deref_trait) support.
+  [@SimonSapin](https://github.com/SimonSapin)
+
+### Changed
+- Mapping of zero-sized files is no longer an error.
+  [@SimonSapin](https://github.com/SimonSapin)
+- MSRV changed from 1.31 to 1.36
+
+## [0.3.1] - 2021-08-15
+### Fixed
+- Integer overflow during file length calculation on 32bit targets.
+- Stub implementation. [@Mrmaxmeier](https://github.com/Mrmaxmeier)
+
+## [0.3.0] - 2021-06-10
+### Changed
+- `MmapOptions` allows mapping using Unix descriptors and not only `std::fs::File` now.
+  [@mripard](https://github.com/mripard)
+
+## [0.2.3] - 2021-05-24
+### Added
+- Allow compilation on unsupported platforms.
+  The code will panic on access just like in `std`.
+  [@jcaesar](https://github.com/jcaesar)
+
+## [0.2.2] - 2021-04-03
+### Added
+- `MmapOptions::populate`. [@adamreichold](https://github.com/adamreichold)
+
+### Fixed
+- Fix alignment computation for `flush_async` to match `flush`.
+  [@adamreichold](https://github.com/adamreichold)
+
+## [0.2.1] - 2021-02-08
+### Added
+- `MmapOptions::map_raw` and `MmapRaw`. [@diwic](https://github.com/diwic)
+
+## [0.2.0] - 2020-12-19
+### Changed
+- MSRV is 1.31 now (edition 2018).
+- Make anonymous memory maps private by default on unix. [@CensoredUsername](https://github.com/CensoredUsername)
+- Add `map_copy_read_only`. [@zseri](https://github.com/zseri)
+
+## 0.1.0 - 2020-01-18
+### Added
+- Fork [memmap-rs](https://github.com/danburkert/memmap-rs).
+
+### Changed
+- Use `LICENSE-APACHE` instead of `README.md` for some tests since it's immutable.
+
+### Removed
+- `winapi` dependency. [memmap-rs/pull/89](https://github.com/danburkert/memmap-rs/pull/89)
+
+[Unreleased]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.8.0...HEAD
+[0.8.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.7.1...v0.8.0
+[0.7.1]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.7.0...v0.7.1
+[0.7.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.6.2...v0.7.0
+[0.6.2]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.6.1...v0.6.2
+[0.6.1]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.6.0...v0.6.1
+[0.6.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.10...v0.6.0
+[0.5.10]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.9...v0.5.10
+[0.5.9]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.8...v0.5.9
+[0.5.8]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.7...v0.5.8
+[0.5.7]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.6...v0.5.7
+[0.5.6]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.5...v0.5.6
+[0.5.5]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.4...v0.5.5
+[0.5.4]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.3...v0.5.4
+[0.5.3]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.2...v0.5.3
+[0.5.2]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.1...v0.5.2
+[0.5.1]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.5.0...v0.5.1
+[0.5.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.4.0...v0.5.0
+[0.4.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.3.1...v0.4.0
+[0.3.1]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.3.0...v0.3.1
+[0.3.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.2.3...v0.3.0
+[0.2.3]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.2.2...v0.2.3
+[0.2.2]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.2.1...v0.2.2
+[0.2.1]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.2.0...v0.2.1
+[0.2.0]: https://github.com/RazrFalcon/memmap2-rs/compare/v0.1.0...v0.2.0
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..894dd2a
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,118 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "fastrand"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
+dependencies = [
+ "instant",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.146"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
+
+[[package]]
+name = "memmap2"
+version = "0.8.0"
+dependencies = [
+ "libc",
+ "owning_ref",
+ "stable_deref_trait",
+ "tempfile",
+]
+
+[[package]]
+name = "owning_ref"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce"
+dependencies = [
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "tempfile"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "libc",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..cf29e5d
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,43 @@
+# 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 are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "memmap2"
+version = "0.8.0"
+authors = [
+    "Dan Burkert <[email protected]>",
+    "Yevhenii Reizner <[email protected]>",
+]
+description = "Cross-platform Rust API for memory-mapped file IO"
+documentation = "https://docs.rs/memmap2"
+readme = "README.md"
+keywords = [
+    "mmap",
+    "memory-map",
+    "io",
+    "file",
+]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/RazrFalcon/memmap2-rs"
+
+[dependencies.stable_deref_trait]
+version = "1.0"
+optional = true
+
+[dev-dependencies.owning_ref]
+version = "0.4.1"
+
+[dev-dependencies.tempfile]
+version = "3"
+
+[target."cfg(unix)".dependencies.libc]
+version = "0.2.143"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..4a878ce
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,20 @@
+[package]
+name = "memmap2"
+version = "0.8.0"
+authors = ["Dan Burkert <[email protected]>", "Yevhenii Reizner <[email protected]>"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/RazrFalcon/memmap2-rs"
+documentation = "https://docs.rs/memmap2"
+description = "Cross-platform Rust API for memory-mapped file IO"
+keywords = ["mmap", "memory-map", "io", "file"]
+edition = "2018"
+
+[dependencies]
+stable_deref_trait = { version = "1.0", optional = true }
+
+[target.'cfg(unix)'.dependencies]
+libc = "0.2.143"
+
+[dev-dependencies]
+tempfile = "3"
+owning_ref = "0.4.1"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..06d842c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,230 @@
+                              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.
+
+-----
+
+Copyright (c) 2020 Yevhenii Reizner
+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/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644
index 0000000..7be3d81
--- /dev/null
+++ b/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/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..6357f40
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright (c) 2020 Yevhenii Reizner
+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/METADATA b/METADATA
new file mode 100644
index 0000000..06379a2
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,21 @@
+name: "memmap2"
+description: "Cross-platform Rust API for memory-mapped file IO"
+third_party {
+  identifier {
+    type: "crates.io"
+    value: "memmap2"
+  }
+  identifier {
+    type: "Archive"
+    value: "https://static.crates.io/crates/memmap2/memmap2-0.8.0.crate"
+    primary_source: true
+  }
+  version: "0.8.0"
+  # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2024
+    month: 1
+    day: 26
+  }
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..5a2b844
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:main:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..df0252b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,33 @@
+# memmap2
+![Build Status](https://github.com/RazrFalcon/memmap2-rs/workflows/Rust/badge.svg)
+[![Crates.io](https://img.shields.io/crates/v/memmap2.svg)](https://crates.io/crates/memmap2)
+[![Documentation](https://docs.rs/memmap2/badge.svg)](https://docs.rs/memmap2)
+[![Rust 1.36+](https://img.shields.io/badge/rust-1.36+-orange.svg)](https://www.rust-lang.org)
+
+A Rust library for cross-platform memory mapped IO.
+
+This is a **fork** of the [memmap-rs](https://github.com/danburkert/memmap-rs) crate.
+
+## 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
+
+A list of supported/tested targets can be found in [Actions](https://github.com/RazrFalcon/memmap2-rs/actions).
+
+## License
+
+`memmap2` 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) 2020 Yevhenii Reizner
+
+Copyright (c) 2015 Dan Burkert
diff --git a/examples/cat.rs b/examples/cat.rs
new file mode 100644
index 0000000..34599af
--- /dev/null
+++ b/examples/cat.rs
@@ -0,0 +1,23 @@
+extern crate memmap2;
+
+use std::env;
+use std::fs::File;
+use std::io::{self, Write};
+
+use memmap2::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/src/advice.rs b/src/advice.rs
new file mode 100644
index 0000000..9b25e4f
--- /dev/null
+++ b/src/advice.rs
@@ -0,0 +1,409 @@
+/// Values supported by [`Mmap::advise`][crate::Mmap::advise] and [`MmapMut::advise`][crate::MmapMut::advise] functions.
+/// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
+#[derive(Debug, Eq, PartialEq, Hash)]
+pub struct Advice(pub(crate) libc::c_int);
+
+impl Advice {
+    /// **MADV_NORMAL**
+    ///
+    /// No special treatment.  This is the default.
+    pub fn normal() -> Self {
+        Self(libc::MADV_NORMAL)
+    }
+
+    /// **MADV_RANDOM**
+    ///
+    /// Expect page references in random order.  (Hence, read
+    /// ahead may be less useful than normally.)
+    pub fn random() -> Self {
+        Self(libc::MADV_RANDOM)
+    }
+
+    /// **MADV_SEQUENTIAL**
+    ///
+    /// Expect page references in sequential order.  (Hence, pages
+    /// in the given range can be aggressively read ahead, and may
+    /// be freed soon after they are accessed.)
+    pub fn sequential() -> Self {
+        Self(libc::MADV_SEQUENTIAL)
+    }
+
+    /// **MADV_WILLNEED**
+    ///
+    /// Expect access in the near future.  (Hence, it might be a
+    /// good idea to read some pages ahead.)
+    pub fn will_need() -> Self {
+        Self(libc::MADV_WILLNEED)
+    }
+
+    /// **MADV_DONTNEED**
+    ///
+    /// Do not expect access in the near future.  (For the time
+    /// being, the application is finished with the given range,
+    /// so the kernel can free resources associated with it.)
+    ///
+    /// After a successful MADV_DONTNEED operation, the semantics
+    /// of memory access in the specified region are changed:
+    /// subsequent accesses of pages in the range will succeed,
+    /// but will result in either repopulating the memory contents
+    /// from the up-to-date contents of the underlying mapped file
+    /// (for shared file mappings, shared anonymous mappings, and
+    /// shmem-based techniques such as System V shared memory
+    /// segments) or zero-fill-on-demand pages for anonymous
+    /// private mappings.
+    ///
+    /// Note that, when applied to shared mappings, MADV_DONTNEED
+    /// might not lead to immediate freeing of the pages in the
+    /// range.  The kernel is free to delay freeing the pages
+    /// until an appropriate moment.  The resident set size (RSS)
+    /// of the calling process will be immediately reduced
+    /// however.
+    ///
+    /// **MADV_DONTNEED** cannot be applied to locked pages, Huge TLB
+    /// pages, or VM_PFNMAP pages.  (Pages marked with the kernel-
+    /// internal VM_PFNMAP flag are special memory areas that are
+    /// not managed by the virtual memory subsystem.  Such pages
+    /// are typically created by device drivers that map the pages
+    /// into user space.)
+    ///
+    /// # Safety
+    ///
+    /// Using the returned value with conceptually write to the
+    /// mapped pages, i.e. borrowing the mapping when the pages
+    /// are freed results in undefined behaviour.
+    pub unsafe fn dont_need() -> Self {
+        Self(libc::MADV_DONTNEED)
+    }
+
+    //
+    // The rest are Linux-specific
+    //
+    /// **MADV_FREE** - Linux (since Linux 4.5) and Darwin
+    ///
+    /// The application no longer requires the pages in the range
+    /// specified by addr and len.  The kernel can thus free these
+    /// pages, but the freeing could be delayed until memory
+    /// pressure occurs.  For each of the pages that has been
+    /// marked to be freed but has not yet been freed, the free
+    /// operation will be canceled if the caller writes into the
+    /// page.  After a successful MADV_FREE operation, any stale
+    /// data (i.e., dirty, unwritten pages) will be lost when the
+    /// kernel frees the pages.  However, subsequent writes to
+    /// pages in the range will succeed and then kernel cannot
+    /// free those dirtied pages, so that the caller can always
+    /// see just written data.  If there is no subsequent write,
+    /// the kernel can free the pages at any time.  Once pages in
+    /// the range have been freed, the caller will see zero-fill-
+    /// on-demand pages upon subsequent page references.
+    ///
+    /// The MADV_FREE operation can be applied only to private
+    /// anonymous pages (see mmap(2)).  In Linux before version
+    /// 4.12, when freeing pages on a swapless system, the pages
+    /// in the given range are freed instantly, regardless of
+    /// memory pressure.
+    ///
+    /// # Safety
+    ///
+    /// Using the returned value with conceptually write to the
+    /// mapped pages, i.e. borrowing the mapping while the pages
+    /// are still being freed results in undefined behaviour.
+    #[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios"))]
+    pub unsafe fn free() -> Self {
+        Self(libc::MADV_FREE)
+    }
+
+    /// **MADV_REMOVE** - Linux only (since Linux 2.6.16)
+    ///
+    /// Free up a given range of pages and its associated backing
+    /// store.  This is equivalent to punching a hole in the
+    /// corresponding byte range of the backing store (see
+    /// fallocate(2)).  Subsequent accesses in the specified
+    /// address range will see bytes containing zero.
+    ///
+    /// The specified address range must be mapped shared and
+    /// writable.  This flag cannot be applied to locked pages,
+    /// Huge TLB pages, or VM_PFNMAP pages.
+    ///
+    /// In the initial implementation, only tmpfs(5) was supported
+    /// **MADV_REMOVE**; but since Linux 3.5, any filesystem which
+    /// supports the fallocate(2) FALLOC_FL_PUNCH_HOLE mode also
+    /// supports MADV_REMOVE.  Hugetlbfs fails with the error
+    /// EINVAL and other filesystems fail with the error
+    /// EOPNOTSUPP.
+    ///
+    /// # Safety
+    ///
+    /// Using the returned value with conceptually write to the
+    /// mapped pages, i.e. borrowing the mapping when the pages
+    /// are freed results in undefined behaviour.
+    #[cfg(target_os = "linux")]
+    pub unsafe fn remove() -> Self {
+        Self(libc::MADV_REMOVE)
+    }
+
+    /// **MADV_DONTFORK** - Linux only (since Linux 2.6.16)
+    ///
+    /// Do not make the pages in this range available to the child
+    /// after a fork(2).  This is useful to prevent copy-on-write
+    /// semantics from changing the physical location of a page if
+    /// the parent writes to it after a fork(2).  (Such page
+    /// relocations cause problems for hardware that DMAs into the
+    /// page.)
+    #[cfg(target_os = "linux")]
+    pub fn dont_fork() -> Self {
+        Self(libc::MADV_DONTFORK)
+    }
+
+    /// **MADV_DOFORK** - Linux only (since Linux 2.6.16)
+    ///
+    /// Undo the effect of MADV_DONTFORK, restoring the default
+    /// behavior, whereby a mapping is inherited across fork(2).
+    #[cfg(target_os = "linux")]
+    pub fn do_fork() -> Self {
+        Self(libc::MADV_DOFORK)
+    }
+
+    /// **MADV_MERGEABLE** - Linux only (since Linux 2.6.32)
+    ///
+    /// Enable Kernel Samepage Merging (KSM) for the pages in the
+    /// range specified by addr and length.  The kernel regularly
+    /// scans those areas of user memory that have been marked as
+    /// mergeable, looking for pages with identical content.
+    /// These are replaced by a single write-protected page (which
+    /// is automatically copied if a process later wants to update
+    /// the content of the page).  KSM merges only private
+    /// anonymous pages (see mmap(2)).
+    ///
+    /// The KSM feature is intended for applications that generate
+    /// many instances of the same data (e.g., virtualization
+    /// systems such as KVM).  It can consume a lot of processing
+    /// power; use with care.  See the Linux kernel source file
+    /// Documentation/admin-guide/mm/ksm.rst for more details.
+    ///
+    /// The MADV_MERGEABLE and MADV_UNMERGEABLE operations are
+    /// available only if the kernel was configured with
+    /// CONFIG_KSM.
+    #[cfg(target_os = "linux")]
+    pub fn mergeable() -> Self {
+        Self(libc::MADV_MERGEABLE)
+    }
+
+    /// **MADV_UNMERGEABLE** - Linux only (since Linux 2.6.32)
+    ///
+    /// Undo the effect of an earlier MADV_MERGEABLE operation on
+    /// the specified address range; KSM unmerges whatever pages
+    /// it had merged in the address range specified by addr and
+    /// length.
+    #[cfg(target_os = "linux")]
+    pub fn unmergeable() -> Self {
+        Self(libc::MADV_UNMERGEABLE)
+    }
+
+    /// **MADV_HUGEPAGE** - Linux only (since Linux 2.6.38)
+    ///
+    /// Enable Transparent Huge Pages (THP) for pages in the range
+    /// specified by addr and length.  Currently, Transparent Huge
+    /// Pages work only with private anonymous pages (see
+    /// mmap(2)).  The kernel will regularly scan the areas marked
+    /// as huge page candidates to replace them with huge pages.
+    /// The kernel will also allocate huge pages directly when the
+    /// region is naturally aligned to the huge page size (see
+    /// posix_memalign(2)).
+    ///
+    /// This feature is primarily aimed at applications that use
+    /// large mappings of data and access large regions of that
+    /// memory at a time (e.g., virtualization systems such as
+    /// QEMU).  It can very easily waste memory (e.g., a 2 MB
+    /// mapping that only ever accesses 1 byte will result in 2 MB
+    /// of wired memory instead of one 4 KB page).  See the Linux
+    /// kernel source file
+    /// Documentation/admin-guide/mm/transhuge.rst for more
+    /// details.
+    ///
+    /// Most common kernels configurations provide MADV_HUGEPAGE-
+    /// style behavior by default, and thus MADV_HUGEPAGE is
+    /// normally not necessary.  It is mostly intended for
+    /// embedded systems, where MADV_HUGEPAGE-style behavior may
+    /// not be enabled by default in the kernel.  On such systems,
+    /// this flag can be used in order to selectively enable THP.
+    /// Whenever MADV_HUGEPAGE is used, it should always be in
+    /// regions of memory with an access pattern that the
+    /// developer knows in advance won't risk to increase the
+    /// memory footprint of the application when transparent
+    /// hugepages are enabled.
+    ///
+    /// The MADV_HUGEPAGE and MADV_NOHUGEPAGE operations are
+    /// available only if the kernel was configured with
+    /// CONFIG_TRANSPARENT_HUGEPAGE.
+    #[cfg(target_os = "linux")]
+    pub fn huge_page() -> Self {
+        Self(libc::MADV_HUGEPAGE)
+    }
+
+    /// **MADV_NOHUGEPAGE** - Linux only (since Linux 2.6.38)
+    ///
+    /// Ensures that memory in the address range specified by addr
+    /// and length will not be backed by transparent hugepages.
+    #[cfg(target_os = "linux")]
+    pub fn no_huge_page() -> Self {
+        Self(libc::MADV_NOHUGEPAGE)
+    }
+
+    /// **MADV_DONTDUMP** - Linux only (since Linux 3.4)
+    ///
+    /// Exclude from a core dump those pages in the range
+    /// specified by addr and length.  This is useful in
+    /// applications that have large areas of memory that are
+    /// known not to be useful in a core dump.  The effect of
+    /// **MADV_DONTDUMP** takes precedence over the bit mask that is
+    /// set via the `/proc/[pid]/coredump_filter` file (see
+    /// core(5)).
+    #[cfg(target_os = "linux")]
+    pub fn dont_dump() -> Self {
+        Self(libc::MADV_DONTDUMP)
+    }
+
+    /// **MADV_DODUMP** - Linux only (since Linux 3.4)
+    ///
+    /// Undo the effect of an earlier MADV_DONTDUMP.
+    #[cfg(target_os = "linux")]
+    pub fn do_dump() -> Self {
+        Self(libc::MADV_DODUMP)
+    }
+
+    /// **MADV_HWPOISON** - Linux only (since Linux 2.6.32)
+    ///
+    /// Poison the pages in the range specified by addr and length
+    /// and handle subsequent references to those pages like a
+    /// hardware memory corruption.  This operation is available
+    /// only for privileged (CAP_SYS_ADMIN) processes.  This
+    /// operation may result in the calling process receiving a
+    /// SIGBUS and the page being unmapped.
+    ///
+    /// This feature is intended for testing of memory error-
+    /// handling code; it is available only if the kernel was
+    /// configured with CONFIG_MEMORY_FAILURE.
+    #[cfg(target_os = "linux")]
+    pub fn hw_poison() -> Self {
+        Self(libc::MADV_HWPOISON)
+    }
+
+    /// **MADV_POPULATE_READ** - Linux only (since Linux 5.14)
+    ///
+    /// Populate  (prefault)  page  tables readable, faulting in all
+    /// pages in the range just as  if  manually  reading  from  each
+    /// page; however, avoid the actual memory access that would have
+    /// been performed after handling the fault.
+    ///
+    /// In contrast to MAP_POPULATE, MADV_POPULATE_READ does not hide
+    /// errors,  can  be  applied to (parts of) existing mappings and
+    /// will always populate (prefault) page  tables  readable.   One
+    /// example  use  case is prefaulting a file mapping, reading all
+    /// file content from disk; however, pages won't be  dirtied  and
+    /// consequently  won't  have  to  be  written  back to disk when
+    /// evicting the pages from memory.
+    ///
+    /// Depending on the underlying mapping, map the shared zeropage,
+    /// preallocate  memory  or  read the underlying file; files with
+    /// holes might or might not preallocate blocks.   If  populating
+    /// fails, a SIGBUS signal is not generated; instead, an error is
+    /// returned.
+    ///
+    /// If MADV_POPULATE_READ succeeds, all  page  tables  have  been
+    /// populated  (prefaulted) readable once.  If MADV_POPULATE_READ
+    /// fails, some page tables might have been populated.
+    ///
+    /// MADV_POPULATE_READ cannot be applied to mappings without read
+    /// permissions  and  special  mappings,  for  example,  mappings
+    /// marked with kernel-internal flags such as VM_PFNMAP or VM_IO,
+    /// or secret memory regions created using memfd_secret(2).
+    ///
+    /// Note  that with MADV_POPULATE_READ, the process can be killed
+    /// at any moment when the system runs out of memory.
+    #[cfg(target_os = "linux")]
+    pub fn populate_read() -> Self {
+        Self(libc::MADV_POPULATE_READ)
+    }
+
+    /// **MADV_POPULATE_WRITE** - Linux only (since Linux 5.14)
+    ///
+    /// Populate (prefault) page tables  writable,  faulting  in  all
+    /// pages  in  the range just as if manually writing to each each
+    /// page; however, avoid the actual memory access that would have
+    /// been performed after handling the fault.
+    ///
+    /// In  contrast  to  MAP_POPULATE,  MADV_POPULATE_WRITE does not
+    /// hide errors, can be applied to (parts of)  existing  mappings
+    /// and  will  always  populate  (prefault) page tables writable.
+    /// One example use case is preallocating  memory,  breaking  any
+    /// CoW (Copy on Write).
+    ///
+    /// Depending  on  the  underlying mapping, preallocate memory or
+    /// read the underlying file; files with holes  will  preallocate
+    /// blocks.   If  populating fails, a SIGBUS signal is not gener‐
+    /// ated; instead, an error is returned.
+    ///
+    /// If MADV_POPULATE_WRITE succeeds, all page  tables  have  been
+    /// populated (prefaulted) writable once.  If MADV_POPULATE_WRITE
+    /// fails, some page tables might have been populated.
+    ///
+    /// MADV_POPULATE_WRITE cannot be  applied  to  mappings  without
+    /// write permissions and special mappings, for example, mappings
+    /// marked with kernel-internal flags such as VM_PFNMAP or VM_IO,
+    /// or secret memory regions created using memfd_secret(2).
+    ///
+    /// Note that with MADV_POPULATE_WRITE, the process can be killed
+    /// at any moment when the system runs out of memory.
+    #[cfg(target_os = "linux")]
+    pub fn populate_write() -> Self {
+        Self(libc::MADV_POPULATE_WRITE)
+    }
+
+    /// **MADV_ZERO_WIRED_PAGES** - Darwin only
+    ///
+    /// Indicates that the application would like the wired pages in this address range to be
+    /// zeroed out if the address range is deallocated without first unwiring the pages (i.e.
+    /// a munmap(2) without a preceding munlock(2) or the application quits).  This is used
+    /// with madvise() system call.
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    pub fn zero_wired_pages() -> Self {
+        Self(libc::MADV_ZERO_WIRED_PAGES)
+    }
+
+    /// **MADV_FREE_REUSABLE** - Darwin only
+    ///
+    /// Behaves like **MADV_FREE**, but the freed pages are accounted for in the RSS of the process.
+    ///
+    /// # Safety
+    ///
+    /// Using the returned value with conceptually write to the
+    /// mapped pages, i.e. borrowing the mapping while the pages
+    /// are still being freed results in undefined behaviour.
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    pub unsafe fn free_reusable() -> Self {
+        Self(libc::MADV_FREE_REUSABLE)
+    }
+
+    /// **MADV_FREE_REUSE** - Darwin only
+    ///
+    /// Marks a memory region previously freed by **MADV_FREE_REUSABLE** as non-reusable, accounts
+    /// for the pages in the RSS of the process. Pages that have been freed will be replaced by
+    /// zero-filled pages on demand, other pages will be left as is.
+    ///
+    /// # Safety
+    ///
+    /// Using the returned value with conceptually write to the
+    /// mapped pages, i.e. borrowing the mapping while the pages
+    /// are still being freed results in undefined behaviour.
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    pub unsafe fn free_reuse() -> Self {
+        Self(libc::MADV_FREE_REUSE)
+    }
+}
+
+// Future expansion:
+// MADV_SOFT_OFFLINE  (since Linux 2.6.33)
+// MADV_WIPEONFORK  (since Linux 4.14)
+// MADV_KEEPONFORK  (since Linux 4.14)
+// MADV_COLD  (since Linux 5.4)
+// MADV_PAGEOUT  (since Linux 5.4)
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..61239be
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,2031 @@
+//! A cross-platform Rust API for memory mapped buffers.
+//!
+//! The core functionality is provided by either [`Mmap`] or [`MmapMut`],
+//! which correspond to mapping a [`File`] to a [`&[u8]`](https://doc.rust-lang.org/std/primitive.slice.html)
+//! or [`&mut [u8]`](https://doc.rust-lang.org/std/primitive.slice.html)
+//! respectively. Both function by dereferencing to a slice, allowing the
+//! [`Mmap`]/[`MmapMut`] to be used in the same way you would the equivalent slice
+//! types.
+//!
+//! [`File`]: std::fs::File
+//!
+//! # Examples
+//!
+//! For simple cases [`Mmap`] can be used directly:
+//!
+//! ```
+//! use std::fs::File;
+//! use std::io::Read;
+//!
+//! use memmap2::Mmap;
+//!
+//! # fn main() -> std::io::Result<()> {
+//! let mut file = File::open("LICENSE-APACHE")?;
+//!
+//! let mut contents = Vec::new();
+//! file.read_to_end(&mut contents)?;
+//!
+//! let mmap = unsafe { Mmap::map(&file)?  };
+//!
+//! assert_eq!(&contents[..], &mmap[..]);
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! However for cases which require configuration of the mapping, then
+//! you can use [`MmapOptions`] in order to further configure a mapping
+//! before you create it.
+
+#![allow(clippy::len_without_is_empty, clippy::missing_safety_doc)]
+
+#[cfg_attr(unix, path = "unix.rs")]
+#[cfg_attr(windows, path = "windows.rs")]
+#[cfg_attr(not(any(unix, windows)), path = "stub.rs")]
+mod os;
+use crate::os::{file_len, MmapInner};
+
+#[cfg(unix)]
+mod advice;
+#[cfg(unix)]
+pub use crate::advice::Advice;
+
+use std::fmt;
+#[cfg(not(any(unix, windows)))]
+use std::fs::File;
+use std::io::{Error, ErrorKind, Result};
+use std::isize;
+use std::mem;
+use std::ops::{Deref, DerefMut};
+#[cfg(unix)]
+use std::os::unix::io::{AsRawFd, RawFd};
+#[cfg(windows)]
+use std::os::windows::io::{AsRawHandle, RawHandle};
+use std::slice;
+
+#[cfg(not(any(unix, windows)))]
+pub struct MmapRawDescriptor<'a>(&'a File);
+
+#[cfg(unix)]
+pub struct MmapRawDescriptor(RawFd);
+
+#[cfg(windows)]
+pub struct MmapRawDescriptor(RawHandle);
+
+pub trait MmapAsRawDesc {
+    fn as_raw_desc(&self) -> MmapRawDescriptor;
+}
+
+#[cfg(not(any(unix, windows)))]
+impl MmapAsRawDesc for &File {
+    fn as_raw_desc(&self) -> MmapRawDescriptor {
+        MmapRawDescriptor(self)
+    }
+}
+
+#[cfg(unix)]
+impl MmapAsRawDesc for RawFd {
+    fn as_raw_desc(&self) -> MmapRawDescriptor {
+        MmapRawDescriptor(*self)
+    }
+}
+
+#[cfg(unix)]
+impl<'a, T> MmapAsRawDesc for &'a T
+where
+    T: AsRawFd,
+{
+    fn as_raw_desc(&self) -> MmapRawDescriptor {
+        MmapRawDescriptor(self.as_raw_fd())
+    }
+}
+
+#[cfg(windows)]
+impl MmapAsRawDesc for RawHandle {
+    fn as_raw_desc(&self) -> MmapRawDescriptor {
+        MmapRawDescriptor(*self)
+    }
+}
+
+#[cfg(windows)]
+impl<'a, T> MmapAsRawDesc for &'a T
+where
+    T: AsRawHandle,
+{
+    fn as_raw_desc(&self) -> MmapRawDescriptor {
+        MmapRawDescriptor(self.as_raw_handle())
+    }
+}
+
+/// 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 [`map_anon()`], or a
+/// file-backed memory map using one of [`map()`], [`map_mut()`], [`map_exec()`],
+/// [`map_copy()`], or [`map_copy_read_only()`].
+///
+/// ## Safety
+///
+/// All file-backed memory map constructors are marked `unsafe` because of the potential for
+/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
+/// out of process. Applications must consider the risk and take appropriate precautions when
+/// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g.
+/// unlinked) files exist but are platform specific and limited.
+///
+/// [`map_anon()`]: MmapOptions::map_anon()
+/// [`map()`]: MmapOptions::map()
+/// [`map_mut()`]: MmapOptions::map_mut()
+/// [`map_exec()`]: MmapOptions::map_exec()
+/// [`map_copy()`]: MmapOptions::map_copy()
+/// [`map_copy_read_only()`]: MmapOptions::map_copy_read_only()
+#[derive(Clone, Debug, Default)]
+pub struct MmapOptions {
+    offset: u64,
+    len: Option<usize>,
+    stack: bool,
+    populate: bool,
+}
+
+impl MmapOptions {
+    /// Creates a new set of options for configuring and creating a memory map.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use memmap2::{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...");
+    /// # 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 memmap2::MmapOptions;
+    /// use std::fs::File;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// let mmap = unsafe {
+    ///     MmapOptions::new()
+    ///                 .offset(30)
+    ///                 .map(&File::open("LICENSE-APACHE")?)?
+    /// };
+    /// assert_eq!(&b"Apache License"[..],
+    ///            &mmap[..14]);
+    /// # 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 memmap2::MmapOptions;
+    /// use std::fs::File;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// let mmap = unsafe {
+    ///     MmapOptions::new()
+    ///                 .len(9)
+    ///                 .map(&File::open("README.md")?)?
+    /// };
+    /// assert_eq!(&b"# memmap2"[..], &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<T: MmapAsRawDesc>(&self, file: &T) -> Result<usize> {
+        self.len.map(Ok).unwrap_or_else(|| {
+            let desc = file.as_raw_desc();
+            let file_len = file_len(desc.0)?;
+
+            if file_len < self.offset {
+                return Err(Error::new(
+                    ErrorKind::InvalidData,
+                    "memory map offset is larger than length",
+                ));
+            }
+            let len = file_len - self.offset;
+
+            // Rust's slice cannot be larger than isize::MAX.
+            // See https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html
+            //
+            // This is not a problem on 64-bit targets, but on 32-bit one
+            // having a file or an anonymous mapping larger than 2GB is quite normal
+            // and we have to prevent it.
+            //
+            // The code below is essentially the same as in Rust's std:
+            // https://github.com/rust-lang/rust/blob/db78ab70a88a0a5e89031d7ee4eccec835dcdbde/library/alloc/src/raw_vec.rs#L495
+            if mem::size_of::<usize>() < 8 && len > isize::MAX as u64 {
+                return Err(Error::new(
+                    ErrorKind::InvalidData,
+                    "memory map length overflows isize",
+                ));
+            }
+
+            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. It has no effect on Windows.
+    ///
+    /// This option has no effect on file-backed memory maps.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use memmap2::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
+    }
+
+    /// Populate (prefault) page tables for a mapping.
+    ///
+    /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later.
+    ///
+    /// This option corresponds to the `MAP_POPULATE` flag on Linux. It has no effect on Windows.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use memmap2::MmapOptions;
+    /// use std::fs::File;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// let file = File::open("LICENSE-MIT")?;
+    ///
+    /// let mmap = unsafe {
+    ///     MmapOptions::new().populate().map(&file)?
+    /// };
+    ///
+    /// assert_eq!(&b"Copyright"[..], &mmap[..9]);
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub fn populate(&mut self) -> &mut Self {
+        self.populate = 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 memmap2::MmapOptions;
+    /// use std::fs::File;
+    /// use std::io::Read;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// let mut file = File::open("LICENSE-APACHE")?;
+    ///
+    /// 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<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> {
+        let desc = file.as_raw_desc();
+
+        MmapInner::map(self.get_len(&file)?, desc.0, self.offset, self.populate)
+            .map(|inner| Mmap { 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<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> {
+        let desc = file.as_raw_desc();
+
+        MmapInner::map_exec(self.get_len(&file)?, desc.0, self.offset, self.populate)
+            .map(|inner| Mmap { 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 memmap2;
+    /// # extern crate tempfile;
+    /// #
+    /// use std::fs::OpenOptions;
+    /// use std::path::PathBuf;
+    ///
+    /// use memmap2::MmapOptions;
+    /// #
+    /// # fn main() -> std::io::Result<()> {
+    /// # let tempdir = tempfile::tempdir()?;
+    /// 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<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut> {
+        let desc = file.as_raw_desc();
+
+        MmapInner::map_mut(self.get_len(&file)?, desc.0, self.offset, self.populate)
+            .map(|inner| MmapMut { 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 memmap2::MmapOptions;
+    /// use std::fs::File;
+    /// use std::io::Write;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// let file = File::open("LICENSE-APACHE")?;
+    /// let mut mmap = unsafe { MmapOptions::new().map_copy(&file)? };
+    /// (&mut mmap[..]).write_all(b"Hello, world!")?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub unsafe fn map_copy<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut> {
+        let desc = file.as_raw_desc();
+
+        MmapInner::map_copy(self.get_len(&file)?, desc.0, self.offset, self.populate)
+            .map(|inner| MmapMut { inner })
+    }
+
+    /// Creates a copy-on-write 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 memmap2::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_copy_read_only(&file)?
+    /// };
+    ///
+    /// assert_eq!(&contents[..], &mmap[..]);
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub unsafe fn map_copy_read_only<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> {
+        let desc = file.as_raw_desc();
+
+        MmapInner::map_copy_read_only(self.get_len(&file)?, desc.0, self.offset, self.populate)
+            .map(|inner| Mmap { inner })
+    }
+
+    /// Creates an anonymous memory map.
+    ///
+    /// The memory map length should be configured using [`MmapOptions::len()`]
+    /// before creating an anonymous memory map, otherwise a zero-length mapping
+    /// will be crated.
+    ///
+    /// # Errors
+    ///
+    /// This method returns an error when the underlying system call fails or
+    /// when `len > isize::MAX`.
+    pub fn map_anon(&self) -> Result<MmapMut> {
+        let len = self.len.unwrap_or(0);
+
+        // See get_len() for details.
+        if mem::size_of::<usize>() < 8 && len > isize::MAX as usize {
+            return Err(Error::new(
+                ErrorKind::InvalidData,
+                "memory map length overflows isize",
+            ));
+        }
+
+        MmapInner::map_anon(len, self.stack, self.populate).map(|inner| MmapMut { inner })
+    }
+
+    /// Creates a raw memory map.
+    ///
+    /// # 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.
+    pub fn map_raw<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapRaw> {
+        let desc = file.as_raw_desc();
+
+        MmapInner::map_mut(self.get_len(&file)?, desc.0, self.offset, self.populate)
+            .map(|inner| MmapRaw { inner })
+    }
+
+    /// Creates a read-only raw memory map
+    ///
+    /// This is primarily useful to avoid intermediate `Mmap` instances when
+    /// read-only access to files modified elsewhere are required.
+    ///
+    /// # Errors
+    ///
+    /// This method returns an error when the underlying system call fails
+    pub fn map_raw_read_only<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapRaw> {
+        let desc = file.as_raw_desc();
+
+        MmapInner::map(self.get_len(&file)?, desc.0, self.offset, self.populate)
+            .map(|inner| MmapRaw { inner })
+    }
+}
+
+/// A handle to 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`] or [`map()`] to create a file-backed memory map. To create an immutable
+/// anonymous memory map, first create a mutable anonymous memory map, and then make it immutable
+/// with [`MmapMut::make_read_only()`].
+///
+/// A file backed `Mmap` is created by `&File` reference, and will remain valid even after the
+/// `File` is dropped. In other words, the `Mmap` handle is completely independent of the `File`
+/// used to create it. For consistency, on some platforms this is achieved by duplicating the
+/// underlying file handle. The memory will be unmapped when the `Mmap` handle is dropped.
+///
+/// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping
+/// the mapped pages into physical memory) though the details of this are platform specific.
+///
+/// `Mmap` is [`Sync`] and [`Send`].
+///
+/// ## Safety
+///
+/// All file-backed memory map constructors are marked `unsafe` because of the potential for
+/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
+/// out of process. Applications must consider the risk and take appropriate precautions when using
+/// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked)
+/// files exist but are platform specific and limited.
+///
+/// ## Example
+///
+/// ```
+/// use memmap2::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"# memmap2", &mmap[0..9]);
+/// # Ok(())
+/// # }
+/// ```
+///
+/// See [`MmapMut`] for the mutable version.
+///
+/// [`map()`]: Mmap::map()
+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 memmap2::Mmap;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// let mut file = File::open("LICENSE-APACHE")?;
+    ///
+    /// 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<T: MmapAsRawDesc>(file: T) -> 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 memmap2;
+    /// # extern crate tempfile;
+    /// #
+    /// use memmap2::Mmap;
+    /// use std::ops::DerefMut;
+    /// use std::io::Write;
+    /// # use std::fs::OpenOptions;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// # let tempdir = tempfile::tempdir()?;
+    /// 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 })
+    }
+
+    /// Advise OS how this memory map will be accessed. Only supported on Unix.
+    ///
+    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
+    #[cfg(unix)]
+    pub fn advise(&self, advice: Advice) -> Result<()> {
+        self.inner.advise(advice, 0, self.inner.len())
+    }
+
+    /// Advise OS how this range of memory map will be accessed.
+    ///
+    /// The offset and length must be in the bounds of the memory map.
+    ///
+    /// Only supported on Unix.
+    ///
+    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
+    #[cfg(unix)]
+    pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> {
+        self.inner.advise(advice, offset, len)
+    }
+
+    /// Lock the whole memory map into RAM. Only supported on Unix.
+    ///
+    /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
+    #[cfg(unix)]
+    pub fn lock(&self) -> Result<()> {
+        self.inner.lock()
+    }
+
+    /// Unlock the whole memory map. Only supported on Unix.
+    ///
+    /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
+    #[cfg(unix)]
+    pub fn unlock(&self) -> Result<()> {
+        self.inner.unlock()
+    }
+
+    /// Adjust the size of the memory mapping.
+    ///
+    /// This will try to resize the memory mapping in place. If
+    /// [`RemapOptions::may_move`] is specified it will move the mapping if it
+    /// could not resize in place, otherwise it will error.
+    ///
+    /// Only supported on Linux.
+    ///
+    /// See the [`mremap(2)`] man page.
+    ///
+    /// # Safety
+    ///
+    /// Resizing the memory mapping beyond the end of the mapped file will
+    /// result in UB should you happen to access memory beyond the end of the
+    /// file.
+    ///
+    /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
+    #[cfg(target_os = "linux")]
+    pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> {
+        self.inner.remap(new_len, options)
+    }
+}
+
+#[cfg(feature = "stable_deref_trait")]
+unsafe impl stable_deref_trait::StableDeref for Mmap {}
+
+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 handle to a raw memory mapped buffer.
+///
+/// This struct never hands out references to its interior, only raw pointers.
+/// This can be helpful when creating shared memory maps between untrusted processes.
+pub struct MmapRaw {
+    inner: MmapInner,
+}
+
+impl MmapRaw {
+    /// Creates a writeable memory map backed by a file.
+    ///
+    /// This is equivalent to calling `MmapOptions::new().map_raw(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.
+    pub fn map_raw<T: MmapAsRawDesc>(file: T) -> Result<MmapRaw> {
+        MmapOptions::new().map_raw(file)
+    }
+
+    /// Returns a raw pointer to the memory mapped file.
+    ///
+    /// Before dereferencing this pointer, you have to make sure that the file has not been
+    /// truncated since the memory map was created.
+    /// Avoiding this will not introduce memory safety issues in Rust terms,
+    /// but will cause SIGBUS (or equivalent) signal.
+    #[inline]
+    pub fn as_ptr(&self) -> *const u8 {
+        self.inner.ptr()
+    }
+
+    /// Returns an unsafe mutable pointer to the memory mapped file.
+    ///
+    /// Before dereferencing this pointer, you have to make sure that the file has not been
+    /// truncated since the memory map was created.
+    /// Avoiding this will not introduce memory safety issues in Rust terms,
+    /// but will cause SIGBUS (or equivalent) signal.
+    #[inline]
+    pub fn as_mut_ptr(&self) -> *mut u8 {
+        self.inner.ptr() as _
+    }
+
+    /// Returns the length in bytes of the memory map.
+    ///
+    /// Note that truncating the file can cause the length to change (and render this value unusable).
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.inner.len()
+    }
+
+    /// 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 memmap2;
+    /// # extern crate tempfile;
+    /// #
+    /// use std::fs::OpenOptions;
+    /// use std::io::Write;
+    /// use std::path::PathBuf;
+    /// use std::slice;
+    ///
+    /// use memmap2::MmapRaw;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// let tempdir = tempfile::tempdir()?;
+    /// 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 { MmapRaw::map_raw(&file)? };
+    ///
+    /// let mut memory = unsafe { slice::from_raw_parts_mut(mmap.as_mut_ptr(), 128) };
+    /// memory.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)
+    }
+
+    /// Advise OS how this memory map will be accessed. Only supported on Unix.
+    ///
+    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
+    #[cfg(unix)]
+    pub fn advise(&self, advice: Advice) -> Result<()> {
+        self.inner.advise(advice, 0, self.inner.len())
+    }
+
+    /// Advise OS how this range of memory map will be accessed.
+    ///
+    /// The offset and length must be in the bounds of the memory map.
+    ///
+    /// Only supported on Unix.
+    ///
+    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
+    #[cfg(unix)]
+    pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> {
+        self.inner.advise(advice, offset, len)
+    }
+
+    /// Lock the whole memory map into RAM. Only supported on Unix.
+    ///
+    /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
+    #[cfg(unix)]
+    pub fn lock(&self) -> Result<()> {
+        self.inner.lock()
+    }
+
+    /// Unlock the whole memory map. Only supported on Unix.
+    ///
+    /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
+    #[cfg(unix)]
+    pub fn unlock(&self) -> Result<()> {
+        self.inner.unlock()
+    }
+
+    /// Adjust the size of the memory mapping.
+    ///
+    /// This will try to resize the memory mapping in place. If
+    /// [`RemapOptions::may_move`] is specified it will move the mapping if it
+    /// could not resize in place, otherwise it will error.
+    ///
+    /// Only supported on Linux.
+    ///
+    /// See the [`mremap(2)`] man page.
+    ///
+    /// # Safety
+    ///
+    /// Resizing the memory mapping beyond the end of the mapped file will
+    /// result in UB should you happen to access memory beyond the end of the
+    /// file.
+    ///
+    /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
+    #[cfg(target_os = "linux")]
+    pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> {
+        self.inner.remap(new_len, options)
+    }
+}
+
+impl fmt::Debug for MmapRaw {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt.debug_struct("MmapRaw")
+            .field("ptr", &self.as_ptr())
+            .field("len", &self.len())
+            .finish()
+    }
+}
+
+impl From<Mmap> for MmapRaw {
+    fn from(value: Mmap) -> Self {
+        Self { inner: value.inner }
+    }
+}
+
+impl From<MmapMut> for MmapRaw {
+    fn from(value: MmapMut) -> Self {
+        Self { inner: value.inner }
+    }
+}
+
+/// A handle to 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
+/// [`MmapMut::map_mut()`] and [`MmapMut::map_anon()`] to create a mutable memory map of the
+/// respective types, or [`MmapOptions::map_mut()`] and [`MmapOptions::map_anon()`] if non-default
+/// options are required.
+///
+/// A file backed `MmapMut` is created by `&File` reference, and will remain valid even after the
+/// `File` is dropped. In other words, the `MmapMut` handle is completely independent of the `File`
+/// used to create it. For consistency, on some platforms this is achieved by duplicating the
+/// underlying file handle. The memory will be unmapped when the `MmapMut` handle is dropped.
+///
+/// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping
+/// the mapped pages into physical memory) though the details of this are platform specific.
+///
+/// `Mmap` is [`Sync`] and [`Send`].
+///
+/// See [`Mmap`] for the immutable version.
+///
+/// ## Safety
+///
+/// All file-backed memory map constructors are marked `unsafe` because of the potential for
+/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
+/// out of process. Applications must consider the risk and take appropriate precautions when using
+/// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked)
+/// files exist but are platform specific and limited.
+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 memmap2;
+    /// # extern crate tempfile;
+    /// #
+    /// use std::fs::OpenOptions;
+    /// use std::path::PathBuf;
+    ///
+    /// use memmap2::MmapMut;
+    /// #
+    /// # fn main() -> std::io::Result<()> {
+    /// # let tempdir = tempfile::tempdir()?;
+    /// 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<T: MmapAsRawDesc>(file: T) -> 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 or
+    /// when `len > isize::MAX`.
+    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 memmap2;
+    /// # extern crate tempfile;
+    /// #
+    /// use std::fs::OpenOptions;
+    /// use std::io::Write;
+    /// use std::path::PathBuf;
+    ///
+    /// use memmap2::MmapMut;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// # let tempdir = tempfile::tempdir()?;
+    /// 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 memmap2;
+    /// #
+    /// use std::io::Write;
+    /// use std::path::PathBuf;
+    ///
+    /// use memmap2::{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.
+    ///
+    /// On systems with separate instructions and data caches (a category that includes many ARM
+    /// chips), a platform-specific call may be needed to ensure that the changes are visible to the
+    /// execution unit (e.g. when using this function to implement a JIT compiler).  For more
+    /// details, see [this ARM write-up](https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/caches-and-self-modifying-code)
+    /// or the `man` page for [`sys_icache_invalidate`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sys_icache_invalidate.3.html).
+    ///
+    /// # 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 })
+    }
+
+    /// Advise OS how this memory map will be accessed. Only supported on Unix.
+    ///
+    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
+    #[cfg(unix)]
+    pub fn advise(&self, advice: Advice) -> Result<()> {
+        self.inner.advise(advice, 0, self.inner.len())
+    }
+
+    /// Advise OS how this range of memory map will be accessed.
+    ///
+    /// The offset and length must be in the bounds of the memory map.
+    ///
+    /// Only supported on Unix.
+    ///
+    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
+    #[cfg(unix)]
+    pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> {
+        self.inner.advise(advice, offset, len)
+    }
+
+    /// Lock the whole memory map into RAM. Only supported on Unix.
+    ///
+    /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
+    #[cfg(unix)]
+    pub fn lock(&self) -> Result<()> {
+        self.inner.lock()
+    }
+
+    /// Unlock the whole memory map. Only supported on Unix.
+    ///
+    /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
+    #[cfg(unix)]
+    pub fn unlock(&self) -> Result<()> {
+        self.inner.unlock()
+    }
+
+    /// Adjust the size of the memory mapping.
+    ///
+    /// This will try to resize the memory mapping in place. If
+    /// [`RemapOptions::may_move`] is specified it will move the mapping if it
+    /// could not resize in place, otherwise it will error.
+    ///
+    /// Only supported on Linux.
+    ///
+    /// See the [`mremap(2)`] man page.
+    ///
+    /// # Safety
+    ///
+    /// Resizing the memory mapping beyond the end of the mapped file will
+    /// result in UB should you happen to access memory beyond the end of the
+    /// file.
+    ///
+    /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
+    #[cfg(target_os = "linux")]
+    pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> {
+        self.inner.remap(new_len, options)
+    }
+}
+
+#[cfg(feature = "stable_deref_trait")]
+unsafe impl stable_deref_trait::StableDeref for MmapMut {}
+
+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()
+    }
+}
+
+/// Options for [`Mmap::remap`] and [`MmapMut::remap`].
+#[derive(Copy, Clone, Default, Debug)]
+#[cfg(target_os = "linux")]
+pub struct RemapOptions {
+    may_move: bool,
+}
+
+#[cfg(target_os = "linux")]
+impl RemapOptions {
+    /// Creates a mew set of options for resizing a memory map.
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// Controls whether the memory map can be moved if it is not possible to
+    /// resize it in place.
+    ///
+    /// If false then the memory map is guaranteed to remain at the same
+    /// address when being resized but attempting to resize will return an
+    /// error if the new memory map would overlap with something else in the
+    /// current process' memory.
+    ///
+    /// By default this is false.
+    ///
+    /// # `may_move` and `StableDeref`
+    /// If the `stable_deref_trait` feature is enabled then [`Mmap`] and
+    /// [`MmapMut`] implement `StableDeref`. `StableDeref` promises that the
+    /// memory map dereferences to a fixed address, however, calling `remap`
+    /// with `may_move` set may result in the backing memory of the mapping
+    /// being moved to a new address. This may cause UB in other code
+    /// depending on the `StableDeref` guarantees.
+    pub fn may_move(mut self, may_move: bool) -> Self {
+        self.may_move = may_move;
+        self
+    }
+
+    pub(crate) fn into_flags(self) -> libc::c_int {
+        if self.may_move {
+            libc::MREMAP_MAYMOVE
+        } else {
+            0
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    extern crate tempfile;
+
+    #[cfg(unix)]
+    use crate::advice::Advice;
+    use std::fs::{File, OpenOptions};
+    use std::io::{Read, Write};
+    use std::mem;
+    #[cfg(unix)]
+    use std::os::unix::io::AsRawFd;
+    #[cfg(windows)]
+    use std::os::windows::fs::OpenOptionsExt;
+
+    #[cfg(windows)]
+    const GENERIC_ALL: u32 = 0x10000000;
+
+    use super::{Mmap, MmapMut, MmapOptions};
+
+    #[test]
+    fn map_file() {
+        let expected_len = 128;
+        let tempdir = tempfile::tempdir().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[..]);
+    }
+
+    #[test]
+    #[cfg(unix)]
+    fn map_fd() {
+        let expected_len = 128;
+        let tempdir = tempfile::tempdir().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.as_raw_fd()).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 "mapping" a 0-length file derefs to an empty slice.
+    #[test]
+    fn map_empty_file() {
+        let tempdir = tempfile::tempdir().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).unwrap() };
+        assert!(mmap.is_empty());
+        assert_eq!(mmap.as_ptr().align_offset(mem::size_of::<usize>()), 0);
+        let mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
+        assert!(mmap.is_empty());
+        assert_eq!(mmap.as_ptr().align_offset(mem::size_of::<usize>()), 0);
+    }
+
+    #[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().unwrap().is_empty())
+    }
+
+    #[test]
+    #[cfg(target_pointer_width = "32")]
+    fn map_anon_len_overflow() {
+        let res = MmapMut::map_anon(0x80000000);
+
+        assert_eq!(
+            res.unwrap_err().to_string(),
+            "memory map length overflows isize"
+        );
+    }
+
+    #[test]
+    fn file_write() {
+        let tempdir = tempfile::tempdir().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_exact(&mut read).unwrap();
+        assert_eq!(write, &read);
+    }
+
+    #[test]
+    fn flush_range() {
+        let tempdir = tempfile::tempdir().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_async_range(0, write.len()).unwrap();
+        mmap.flush_range(0, write.len()).unwrap();
+    }
+
+    #[test]
+    fn map_copy() {
+        let tempdir = tempfile::tempdir().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_all(write).unwrap();
+        mmap.flush().unwrap();
+
+        // The mmap contains the write
+        (&mmap[..]).read_exact(&mut read).unwrap();
+        assert_eq!(write, &read);
+
+        // The file does not contain the write
+        file.read_exact(&mut read).unwrap();
+        assert_eq!(nulls, &read);
+
+        // another mmap does not contain the write
+        let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
+        (&mmap2[..]).read_exact(&mut read).unwrap();
+        assert_eq!(nulls, &read);
+    }
+
+    #[test]
+    fn map_copy_read_only() {
+        let tempdir = tempfile::tempdir().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 nulls = b"\0\0\0\0\0\0";
+        let mut read = [0u8; 6];
+
+        let mmap = unsafe { MmapOptions::new().map_copy_read_only(&file).unwrap() };
+        (&mmap[..]).read_exact(&mut read).unwrap();
+        assert_eq!(nulls, &read);
+
+        let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
+        (&mmap2[..]).read_exact(&mut read).unwrap();
+        assert_eq!(nulls, &read);
+    }
+
+    #[test]
+    fn map_offset() {
+        let tempdir = tempfile::tempdir().unwrap();
+        let path = tempdir.path().join("mmap");
+
+        let file = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(true)
+            .open(path)
+            .unwrap();
+
+        let offset = u32::MAX 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 = MmapMut::map_anon(129).unwrap();
+
+        fn is_sync_send<T>(_val: T)
+        where
+            T: Sync + Send,
+        {
+        }
+
+        is_sync_send(mmap);
+    }
+
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    fn jit_x86(mut mmap: MmapMut) {
+        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 = tempfile::tempdir().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 = tempfile::tempdir().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_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_all(write).unwrap();
+        mmap.flush().unwrap();
+
+        // The mmap contains the write
+        (&mmap[..]).read_exact(&mut read).unwrap();
+        assert_eq!(write, &read);
+
+        // The file should contain the write
+        file.read_exact(&mut read).unwrap();
+        assert_eq!(write, &read);
+
+        // another mmap should contain the write
+        let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
+        (&mmap2[..]).read_exact(&mut read).unwrap();
+        assert_eq!(write, &read);
+
+        let mmap = mmap.make_exec().expect("make_exec");
+
+        drop(mmap);
+    }
+
+    #[test]
+    fn mprotect_copy() {
+        let tempdir = tempfile::tempdir().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_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_all(write).unwrap();
+        mmap.flush().unwrap();
+
+        // The mmap contains the write
+        (&mmap[..]).read_exact(&mut read).unwrap();
+        assert_eq!(write, &read);
+
+        // The file does not contain the write
+        file.read_exact(&mut read).unwrap();
+        assert_eq!(nulls, &read);
+
+        // another mmap does not contain the write
+        let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
+        (&mmap2[..]).read_exact(&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);
+    }
+
+    #[test]
+    fn raw() {
+        let tempdir = tempfile::tempdir().unwrap();
+        let path = tempdir.path().join("mmapraw");
+
+        let mut options = OpenOptions::new();
+        let mut file = options
+            .read(true)
+            .write(true)
+            .create(true)
+            .open(path)
+            .expect("open");
+        file.write_all(b"abc123").unwrap();
+        let mmap = MmapOptions::new().map_raw(&file).unwrap();
+        assert_eq!(mmap.len(), 6);
+        assert!(!mmap.as_ptr().is_null());
+        assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a');
+    }
+
+    #[test]
+    fn raw_read_only() {
+        let tempdir = tempfile::tempdir().unwrap();
+        let path = tempdir.path().join("mmaprawro");
+
+        File::create(&path).unwrap().write_all(b"abc123").unwrap();
+
+        let mmap = MmapOptions::new()
+            .map_raw_read_only(&File::open(&path).unwrap())
+            .unwrap();
+
+        assert_eq!(mmap.len(), 6);
+        assert!(!mmap.as_ptr().is_null());
+        assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a');
+    }
+
+    /// Something that relies on StableDeref
+    #[test]
+    #[cfg(feature = "stable_deref_trait")]
+    fn owning_ref() {
+        extern crate owning_ref;
+
+        let mut map = MmapMut::map_anon(128).unwrap();
+        map[10] = 42;
+        let owning = owning_ref::OwningRef::new(map);
+        let sliced = owning.map(|map| &map[10..20]);
+        assert_eq!(42, sliced[0]);
+
+        let map = sliced.into_owner().make_read_only().unwrap();
+        let owning = owning_ref::OwningRef::new(map);
+        let sliced = owning.map(|map| &map[10..20]);
+        assert_eq!(42, sliced[0]);
+    }
+
+    #[test]
+    #[cfg(unix)]
+    fn advise() {
+        let expected_len = 128;
+        let tempdir = tempfile::tempdir().unwrap();
+        let path = tempdir.path().join("mmap_advise");
+
+        let file = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(true)
+            .open(path)
+            .unwrap();
+
+        file.set_len(expected_len as u64).unwrap();
+
+        // Test MmapMut::advise
+        let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
+        mmap.advise(Advice::random())
+            .expect("mmap advising should be supported on unix");
+
+        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[..]);
+
+        mmap.advise_range(Advice::sequential(), 0, mmap.len())
+            .expect("mmap advising should be supported on unix");
+
+        // write values into the mmap
+        (&mut mmap[..]).write_all(&incr[..]).unwrap();
+
+        // read values back
+        assert_eq!(&incr[..], &mmap[..]);
+
+        // Set advice and Read from the read-only map
+        let mmap = unsafe { Mmap::map(&file).unwrap() };
+
+        mmap.advise(Advice::random())
+            .expect("mmap advising should be supported on unix");
+
+        // read values back
+        assert_eq!(&incr[..], &mmap[..]);
+    }
+
+    #[test]
+    #[cfg(target_os = "linux")]
+    fn advise_writes_unsafely() {
+        let mut mmap = MmapMut::map_anon(4096).unwrap();
+        mmap.as_mut().fill(255);
+        let mmap = mmap.make_read_only().unwrap();
+
+        let a = mmap.as_ref()[0];
+        mmap.advise(unsafe { Advice::dont_need() }).unwrap();
+        let b = mmap.as_ref()[0];
+
+        assert_eq!(a, 255);
+        assert_eq!(b, 0);
+    }
+
+    /// Returns true if a non-zero amount of memory is locked.
+    #[cfg(target_os = "linux")]
+    fn is_locked() -> bool {
+        let status = &std::fs::read_to_string("/proc/self/status")
+            .expect("/proc/self/status should be available");
+        for line in status.lines() {
+            if line.starts_with("VmLck:") {
+                let numbers = line.replace(|c: char| !c.is_ascii_digit(), "");
+                return numbers != "0";
+            }
+        }
+        panic!("cannot get VmLck information")
+    }
+
+    #[test]
+    #[cfg(unix)]
+    fn lock() {
+        let tempdir = tempfile::tempdir().unwrap();
+        let path = tempdir.path().join("mmap_lock");
+
+        let file = OpenOptions::new()
+            .read(true)
+            .write(true)
+            .create(true)
+            .open(path)
+            .unwrap();
+        file.set_len(128).unwrap();
+
+        let mmap = unsafe { Mmap::map(&file).unwrap() };
+        #[cfg(target_os = "linux")]
+        assert!(!is_locked());
+
+        mmap.lock().expect("mmap lock should be supported on unix");
+        #[cfg(target_os = "linux")]
+        assert!(is_locked());
+
+        mmap.lock()
+            .expect("mmap lock again should not cause problems");
+        #[cfg(target_os = "linux")]
+        assert!(is_locked());
+
+        mmap.unlock()
+            .expect("mmap unlock should be supported on unix");
+        #[cfg(target_os = "linux")]
+        assert!(!is_locked());
+
+        mmap.unlock()
+            .expect("mmap unlock again should not cause problems");
+        #[cfg(target_os = "linux")]
+        assert!(!is_locked());
+    }
+
+    #[test]
+    #[cfg(target_os = "linux")]
+    fn remap_grow() {
+        use crate::RemapOptions;
+
+        let initial_len = 128;
+        let final_len = 2000;
+
+        let zeros = vec![0u8; final_len];
+        let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect();
+
+        let file = tempfile::tempfile().unwrap();
+        file.set_len(final_len as u64).unwrap();
+
+        let mut mmap = unsafe { MmapOptions::new().len(initial_len).map_mut(&file).unwrap() };
+        assert_eq!(mmap.len(), initial_len);
+        assert_eq!(&mmap[..], &zeros[..initial_len]);
+
+        unsafe {
+            mmap.remap(final_len, RemapOptions::new().may_move(true))
+                .unwrap()
+        };
+
+        // The size should have been updated
+        assert_eq!(mmap.len(), final_len);
+
+        // Should still be all zeros
+        assert_eq!(&mmap[..], &zeros);
+
+        // Write out to the whole expanded slice.
+        mmap.copy_from_slice(&incr);
+    }
+
+    #[test]
+    #[cfg(target_os = "linux")]
+    fn remap_shrink() {
+        use crate::RemapOptions;
+
+        let initial_len = 20000;
+        let final_len = 400;
+
+        let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect();
+
+        let file = tempfile::tempfile().unwrap();
+        file.set_len(initial_len as u64).unwrap();
+
+        let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
+        assert_eq!(mmap.len(), initial_len);
+
+        unsafe { mmap.remap(final_len, RemapOptions::new()).unwrap() };
+        assert_eq!(mmap.len(), final_len);
+
+        // Check that the mmap is still writable along the slice length
+        mmap.copy_from_slice(&incr);
+    }
+
+    #[test]
+    #[cfg(target_os = "linux")]
+    #[cfg(target_pointer_width = "32")]
+    fn remap_len_overflow() {
+        use crate::RemapOptions;
+
+        let file = tempfile::tempfile().unwrap();
+        file.set_len(1024).unwrap();
+        let mut mmap = unsafe { MmapOptions::new().len(1024).map(&file).unwrap() };
+
+        let res = unsafe { mmap.remap(0x80000000, RemapOptions::new().may_move(true)) };
+        assert_eq!(
+            res.unwrap_err().to_string(),
+            "memory map length overflows isize"
+        );
+
+        assert_eq!(mmap.len(), 1024);
+    }
+
+    #[test]
+    #[cfg(target_os = "linux")]
+    fn remap_with_offset() {
+        use crate::RemapOptions;
+
+        let offset = 77;
+        let initial_len = 128;
+        let final_len = 2000;
+
+        let zeros = vec![0u8; final_len];
+        let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect();
+
+        let file = tempfile::tempfile().unwrap();
+        file.set_len(final_len as u64 + offset).unwrap();
+
+        let mut mmap = unsafe {
+            MmapOptions::new()
+                .len(initial_len)
+                .offset(offset)
+                .map_mut(&file)
+                .unwrap()
+        };
+        assert_eq!(mmap.len(), initial_len);
+        assert_eq!(&mmap[..], &zeros[..initial_len]);
+
+        unsafe {
+            mmap.remap(final_len, RemapOptions::new().may_move(true))
+                .unwrap()
+        };
+
+        // The size should have been updated
+        assert_eq!(mmap.len(), final_len);
+
+        // Should still be all zeros
+        assert_eq!(&mmap[..], &zeros);
+
+        // Write out to the whole expanded slice.
+        mmap.copy_from_slice(&incr);
+    }
+}
diff --git a/src/stub.rs b/src/stub.rs
new file mode 100644
index 0000000..3c6af0e
--- /dev/null
+++ b/src/stub.rs
@@ -0,0 +1,81 @@
+use std::fs::File;
+use std::io;
+
+// A stable alternative to https://doc.rust-lang.org/stable/std/primitive.never.html
+enum Never {}
+
+pub struct MmapInner {
+    never: Never,
+}
+
+impl MmapInner {
+    fn new() -> io::Result<MmapInner> {
+        Err(io::Error::new(
+            io::ErrorKind::Other,
+            "platform not supported",
+        ))
+    }
+
+    pub fn map(_: usize, _: &File, _: u64, _: bool) -> io::Result<MmapInner> {
+        MmapInner::new()
+    }
+
+    pub fn map_exec(_: usize, _: &File, _: u64, _: bool) -> io::Result<MmapInner> {
+        MmapInner::new()
+    }
+
+    pub fn map_mut(_: usize, _: &File, _: u64, _: bool) -> io::Result<MmapInner> {
+        MmapInner::new()
+    }
+
+    pub fn map_copy(_: usize, _: &File, _: u64, _: bool) -> io::Result<MmapInner> {
+        MmapInner::new()
+    }
+
+    pub fn map_copy_read_only(_: usize, _: &File, _: u64, _: bool) -> io::Result<MmapInner> {
+        MmapInner::new()
+    }
+
+    pub fn map_anon(_: usize, _: bool, _: bool) -> io::Result<MmapInner> {
+        MmapInner::new()
+    }
+
+    pub fn flush(&self, _: usize, _: usize) -> io::Result<()> {
+        match self.never {}
+    }
+
+    pub fn flush_async(&self, _: usize, _: usize) -> io::Result<()> {
+        match self.never {}
+    }
+
+    pub fn make_read_only(&mut self) -> io::Result<()> {
+        match self.never {}
+    }
+
+    pub fn make_exec(&mut self) -> io::Result<()> {
+        match self.never {}
+    }
+
+    pub fn make_mut(&mut self) -> io::Result<()> {
+        match self.never {}
+    }
+
+    #[inline]
+    pub fn ptr(&self) -> *const u8 {
+        match self.never {}
+    }
+
+    #[inline]
+    pub fn mut_ptr(&mut self) -> *mut u8 {
+        match self.never {}
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        match self.never {}
+    }
+}
+
+pub fn file_len(file: &File) -> io::Result<u64> {
+    Ok(file.metadata()?.len())
+}
diff --git a/src/unix.rs b/src/unix.rs
new file mode 100644
index 0000000..3761b27
--- /dev/null
+++ b/src/unix.rs
@@ -0,0 +1,433 @@
+extern crate libc;
+
+use std::fs::File;
+use std::mem::ManuallyDrop;
+use std::os::unix::io::{FromRawFd, RawFd};
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::{io, ptr};
+
+use crate::advice::Advice;
+
+#[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;
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+const MAP_POPULATE: libc::c_int = libc::MAP_POPULATE;
+
+#[cfg(not(any(target_os = "linux", target_os = "android")))]
+const MAP_POPULATE: libc::c_int = 0;
+
+#[cfg(any(
+    target_os = "android",
+    all(target_os = "linux", not(target_env = "musl"))
+))]
+use libc::{mmap64 as mmap, off64_t as off_t};
+
+#[cfg(not(any(
+    target_os = "android",
+    all(target_os = "linux", not(target_env = "musl"))
+)))]
+use libc::{mmap, off_t};
+
+pub struct MmapInner {
+    ptr: *mut libc::c_void,
+    len: usize,
+}
+
+impl MmapInner {
+    /// Creates a new `MmapInner`.
+    ///
+    /// This is a thin wrapper around the `mmap` system 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 (map_len, map_offset) = Self::adjust_mmap_params(len, alignment as usize)?;
+
+        unsafe {
+            let ptr = mmap(
+                ptr::null_mut(),
+                map_len as libc::size_t,
+                prot,
+                flags,
+                file,
+                aligned_offset as off_t,
+            );
+
+            if ptr == libc::MAP_FAILED {
+                Err(io::Error::last_os_error())
+            } else {
+                Ok(Self::from_raw_parts(ptr, len, map_offset))
+            }
+        }
+    }
+
+    fn adjust_mmap_params(len: usize, alignment: usize) -> io::Result<(usize, usize)> {
+        use std::isize;
+
+        // Rust's slice cannot be larger than isize::MAX.
+        // See https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html
+        //
+        // This is not a problem on 64-bit targets, but on 32-bit one
+        // having a file or an anonymous mapping larger than 2GB is quite normal
+        // and we have to prevent it.
+        //
+        // The code below is essentially the same as in Rust's std:
+        // https://github.com/rust-lang/rust/blob/db78ab70a88a0a5e89031d7ee4eccec835dcdbde/library/alloc/src/raw_vec.rs#L495
+        if std::mem::size_of::<usize>() < 8 && len > isize::MAX as usize {
+            return Err(io::Error::new(
+                io::ErrorKind::InvalidData,
+                "memory map length overflows isize",
+            ));
+        }
+
+        let map_len = len + alignment;
+        let map_offset = alignment;
+
+        // `libc::mmap` does not support zero-size mappings. POSIX defines:
+        //
+        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html
+        // > If `len` is zero, `mmap()` shall fail and no mapping shall be established.
+        //
+        // So if we would create such a mapping, crate a one-byte mapping instead:
+        let map_len = map_len.max(1);
+
+        // Note that in that case `MmapInner::len` is still set to zero,
+        // and `Mmap` will still dereferences to an empty slice.
+        //
+        // If this mapping is backed by an empty file, we create a mapping larger than the file.
+        // This is unusual but well-defined. On the same man page, POSIX further defines:
+        //
+        // > The `mmap()` function can be used to map a region of memory that is larger
+        // > than the current size of the object.
+        //
+        // (The object here is the file.)
+        //
+        // > Memory access within the mapping but beyond the current end of the underlying
+        // > objects may result in SIGBUS signals being sent to the process. The reason for this
+        // > is that the size of the object can be manipulated by other processes and can change
+        // > at any moment. The implementation should tell the application that a memory reference
+        // > is outside the object where this can be detected; otherwise, written data may be lost
+        // > and read data may not reflect actual data in the object.
+        //
+        // Because `MmapInner::len` is not incremented, this increment of `aligned_len`
+        // will not allow accesses past the end of the file and will not cause SIGBUS.
+        //
+        // (SIGBUS is still possible by mapping a non-empty file and then truncating it
+        // to a shorter size, but that is unrelated to this handling of empty files.)
+        Ok((map_len, map_offset))
+    }
+
+    /// Get the current memory mapping as a `(ptr, map_len, offset)` tuple.
+    ///
+    /// Note that `map_len` is the length of the memory mapping itself and
+    /// _not_ the one that would be passed to `from_raw_parts`.
+    fn as_mmap_params(&self) -> (*mut libc::c_void, usize, usize) {
+        let offset = self.ptr as usize % page_size();
+        let len = self.len + offset;
+
+        // There are two possible memory layouts we could have, depending on
+        // the length and offset passed when constructing this instance:
+        //
+        // 1. The "normal" memory layout looks like this:
+        //
+        //         |<------------------>|<---------------------->|
+        //     mmap ptr    offset      ptr     public slice
+        //
+        //    That is, we have
+        //    - The start of the page-aligned memory mapping returned by mmap,
+        //      followed by,
+        //    - Some number of bytes that are memory mapped but ignored since
+        //      they are before the byte offset requested by the user, followed
+        //      by,
+        //    - The actual memory mapped slice requested by the user.
+        //
+        //    This maps cleanly to a (ptr, len, offset) tuple.
+        //
+        // 2. Then, we have the case where the user requested a zero-length
+        //    memory mapping. mmap(2) does not support zero-length mappings so
+        //    this crate works around that by actually making a mapping of
+        //    length one. This means that we have
+        //    - A length zero slice, followed by,
+        //    - A single memory mapped byte
+        //
+        //    Note that this only happens if the offset within the page is also
+        //    zero. Otherwise, we have a memory map of offset bytes and not a
+        //    zero-length memory map.
+        //
+        //    This doesn't fit cleanly into a (ptr, len, offset) tuple. Instead,
+        //    we fudge it slightly: a zero-length memory map turns into a
+        //    mapping of length one and can't be told apart outside of this
+        //    method without knowing the original length.
+        if len == 0 {
+            (self.ptr, 1, 0)
+        } else {
+            (unsafe { self.ptr.offset(-(offset as isize)) }, len, offset)
+        }
+    }
+
+    /// Construct this `MmapInner` from its raw components
+    ///
+    /// # Safety
+    ///
+    /// - `ptr` must point to the start of memory mapping that can be freed
+    ///   using `munmap(2)` (i.e. returned by `mmap(2)` or `mremap(2)`)
+    /// - The memory mapping at `ptr` must have a length of `len + offset`.
+    /// - If `len + offset == 0` then the memory mapping must be of length 1.
+    /// - `offset` must be less than the current page size.
+    unsafe fn from_raw_parts(ptr: *mut libc::c_void, len: usize, offset: usize) -> Self {
+        debug_assert_eq!(ptr as usize % page_size(), 0, "ptr not page-aligned");
+        debug_assert!(offset < page_size(), "offset larger than page size");
+
+        Self {
+            ptr: ptr.add(offset),
+            len,
+        }
+    }
+
+    pub fn map(len: usize, file: RawFd, offset: u64, populate: bool) -> io::Result<MmapInner> {
+        let populate = if populate { MAP_POPULATE } else { 0 };
+        MmapInner::new(
+            len,
+            libc::PROT_READ,
+            libc::MAP_SHARED | populate,
+            file,
+            offset,
+        )
+    }
+
+    pub fn map_exec(len: usize, file: RawFd, offset: u64, populate: bool) -> io::Result<MmapInner> {
+        let populate = if populate { MAP_POPULATE } else { 0 };
+        MmapInner::new(
+            len,
+            libc::PROT_READ | libc::PROT_EXEC,
+            libc::MAP_SHARED | populate,
+            file,
+            offset,
+        )
+    }
+
+    pub fn map_mut(len: usize, file: RawFd, offset: u64, populate: bool) -> io::Result<MmapInner> {
+        let populate = if populate { MAP_POPULATE } else { 0 };
+        MmapInner::new(
+            len,
+            libc::PROT_READ | libc::PROT_WRITE,
+            libc::MAP_SHARED | populate,
+            file,
+            offset,
+        )
+    }
+
+    pub fn map_copy(len: usize, file: RawFd, offset: u64, populate: bool) -> io::Result<MmapInner> {
+        let populate = if populate { MAP_POPULATE } else { 0 };
+        MmapInner::new(
+            len,
+            libc::PROT_READ | libc::PROT_WRITE,
+            libc::MAP_PRIVATE | populate,
+            file,
+            offset,
+        )
+    }
+
+    pub fn map_copy_read_only(
+        len: usize,
+        file: RawFd,
+        offset: u64,
+        populate: bool,
+    ) -> io::Result<MmapInner> {
+        let populate = if populate { MAP_POPULATE } else { 0 };
+        MmapInner::new(
+            len,
+            libc::PROT_READ,
+            libc::MAP_PRIVATE | populate,
+            file,
+            offset,
+        )
+    }
+
+    /// Open an anonymous memory map.
+    pub fn map_anon(len: usize, stack: bool, populate: bool) -> io::Result<MmapInner> {
+        let stack = if stack { MAP_STACK } else { 0 };
+        let populate = if populate { MAP_POPULATE } else { 0 };
+        MmapInner::new(
+            len,
+            libc::PROT_READ | libc::PROT_WRITE,
+            libc::MAP_PRIVATE | libc::MAP_ANON | stack | populate,
+            -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 = (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_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;
+            let len = len.max(1);
+            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
+    }
+
+    pub fn advise(&self, advice: Advice, 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;
+        unsafe {
+            if libc::madvise(self.ptr.offset(offset), len, advice.0) != 0 {
+                Err(io::Error::last_os_error())
+            } else {
+                Ok(())
+            }
+        }
+    }
+
+    #[cfg(target_os = "linux")]
+    pub fn remap(&mut self, new_len: usize, options: crate::RemapOptions) -> io::Result<()> {
+        let (old_ptr, old_len, offset) = self.as_mmap_params();
+        let (map_len, offset) = Self::adjust_mmap_params(new_len, offset)?;
+
+        unsafe {
+            let new_ptr = libc::mremap(old_ptr, old_len, map_len, options.into_flags());
+
+            if new_ptr == libc::MAP_FAILED {
+                Err(io::Error::last_os_error())
+            } else {
+                // We explicitly don't drop self since the pointer within is no longer valid.
+                ptr::write(self, Self::from_raw_parts(new_ptr, new_len, offset));
+                Ok(())
+            }
+        }
+    }
+
+    pub fn lock(&self) -> io::Result<()> {
+        unsafe {
+            if libc::mlock(self.ptr, self.len) != 0 {
+                Err(io::Error::last_os_error())
+            } else {
+                Ok(())
+            }
+        }
+    }
+
+    pub fn unlock(&self) -> io::Result<()> {
+        unsafe {
+            if libc::munlock(self.ptr, self.len) != 0 {
+                Err(io::Error::last_os_error())
+            } else {
+                Ok(())
+            }
+        }
+    }
+}
+
+impl Drop for MmapInner {
+    fn drop(&mut self) {
+        let (ptr, len, _) = self.as_mmap_params();
+
+        // Any errors during unmapping/closing are ignored as the only way
+        // to report them would be through panicking which is highly discouraged
+        // in Drop impls, c.f. https://github.com/rust-lang/lang-team/issues/97
+        unsafe { libc::munmap(ptr, len as libc::size_t) };
+    }
+}
+
+unsafe impl Sync for MmapInner {}
+unsafe impl Send for MmapInner {}
+
+fn page_size() -> usize {
+    static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
+
+    match PAGE_SIZE.load(Ordering::Relaxed) {
+        0 => {
+            let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
+
+            PAGE_SIZE.store(page_size, Ordering::Relaxed);
+
+            page_size
+        }
+        page_size => page_size,
+    }
+}
+
+pub fn file_len(file: RawFd) -> io::Result<u64> {
+    // SAFETY: We must not close the passed-in fd by dropping the File we create,
+    // we ensure this by immediately wrapping it in a ManuallyDrop.
+    unsafe {
+        let file = ManuallyDrop::new(File::from_raw_fd(file));
+        Ok(file.metadata()?.len())
+    }
+}
diff --git a/src/windows.rs b/src/windows.rs
new file mode 100644
index 0000000..5373369
--- /dev/null
+++ b/src/windows.rs
@@ -0,0 +1,519 @@
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+use std::fs::File;
+use std::mem::ManuallyDrop;
+use std::os::raw::c_void;
+use std::os::windows::io::{FromRawHandle, RawHandle};
+use std::{io, mem, ptr};
+
+type BOOL = i32;
+type WORD = u16;
+type DWORD = u32;
+type WCHAR = u16;
+type HANDLE = *mut c_void;
+type LPHANDLE = *mut HANDLE;
+type LPVOID = *mut c_void;
+type LPCVOID = *const c_void;
+type ULONG_PTR = usize;
+type SIZE_T = ULONG_PTR;
+type LPCWSTR = *const WCHAR;
+type PDWORD = *mut DWORD;
+type DWORD_PTR = ULONG_PTR;
+type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
+type LPSYSTEM_INFO = *mut SYSTEM_INFO;
+
+const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE;
+
+const DUPLICATE_SAME_ACCESS: DWORD = 0x00000002;
+
+const STANDARD_RIGHTS_REQUIRED: DWORD = 0x000F0000;
+
+const SECTION_QUERY: DWORD = 0x0001;
+const SECTION_MAP_WRITE: DWORD = 0x0002;
+const SECTION_MAP_READ: DWORD = 0x0004;
+const SECTION_MAP_EXECUTE: DWORD = 0x0008;
+const SECTION_EXTEND_SIZE: DWORD = 0x0010;
+const SECTION_MAP_EXECUTE_EXPLICIT: DWORD = 0x0020;
+const SECTION_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED
+    | SECTION_QUERY
+    | SECTION_MAP_WRITE
+    | SECTION_MAP_READ
+    | SECTION_MAP_EXECUTE
+    | SECTION_EXTEND_SIZE;
+
+const PAGE_READONLY: DWORD = 0x02;
+const PAGE_READWRITE: DWORD = 0x04;
+const PAGE_WRITECOPY: DWORD = 0x08;
+const PAGE_EXECUTE_READ: DWORD = 0x20;
+const PAGE_EXECUTE_READWRITE: DWORD = 0x40;
+const PAGE_EXECUTE_WRITECOPY: DWORD = 0x80;
+
+const FILE_MAP_WRITE: DWORD = SECTION_MAP_WRITE;
+const FILE_MAP_READ: DWORD = SECTION_MAP_READ;
+const FILE_MAP_ALL_ACCESS: DWORD = SECTION_ALL_ACCESS;
+const FILE_MAP_EXECUTE: DWORD = SECTION_MAP_EXECUTE_EXPLICIT;
+const FILE_MAP_COPY: DWORD = 0x00000001;
+
+#[repr(C)]
+struct SECURITY_ATTRIBUTES {
+    nLength: DWORD,
+    lpSecurityDescriptor: LPVOID,
+    bInheritHandle: BOOL,
+}
+
+#[repr(C)]
+struct SYSTEM_INFO {
+    wProcessorArchitecture: WORD,
+    wReserved: WORD,
+    dwPageSize: DWORD,
+    lpMinimumApplicationAddress: LPVOID,
+    lpMaximumApplicationAddress: LPVOID,
+    dwActiveProcessorMask: DWORD_PTR,
+    dwNumberOfProcessors: DWORD,
+    dwProcessorType: DWORD,
+    dwAllocationGranularity: DWORD,
+    wProcessorLevel: WORD,
+    wProcessorRevision: WORD,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct FILETIME {
+    pub dwLowDateTime: DWORD,
+    pub dwHighDateTime: DWORD,
+}
+
+extern "system" {
+    fn GetCurrentProcess() -> HANDLE;
+
+    fn CloseHandle(hObject: HANDLE) -> BOOL;
+
+    fn DuplicateHandle(
+        hSourceProcessHandle: HANDLE,
+        hSourceHandle: HANDLE,
+        hTargetProcessHandle: HANDLE,
+        lpTargetHandle: LPHANDLE,
+        dwDesiredAccess: DWORD,
+        bInheritHandle: BOOL,
+        dwOptions: DWORD,
+    ) -> BOOL;
+
+    fn CreateFileMappingW(
+        hFile: HANDLE,
+        lpFileMappingAttributes: LPSECURITY_ATTRIBUTES,
+        flProtect: DWORD,
+        dwMaximumSizeHigh: DWORD,
+        dwMaximumSizeLow: DWORD,
+        lpName: LPCWSTR,
+    ) -> HANDLE;
+
+    fn FlushFileBuffers(hFile: HANDLE) -> BOOL;
+
+    fn FlushViewOfFile(lpBaseAddress: LPCVOID, dwNumberOfBytesToFlush: SIZE_T) -> BOOL;
+
+    fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
+
+    fn MapViewOfFile(
+        hFileMappingObject: HANDLE,
+        dwDesiredAccess: DWORD,
+        dwFileOffsetHigh: DWORD,
+        dwFileOffsetLow: DWORD,
+        dwNumberOfBytesToMap: SIZE_T,
+    ) -> LPVOID;
+
+    fn VirtualProtect(
+        lpAddress: LPVOID,
+        dwSize: SIZE_T,
+        flNewProtect: DWORD,
+        lpflOldProtect: PDWORD,
+    ) -> BOOL;
+
+    fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);
+}
+
+/// Returns a fixed aligned pointer that is valid for `slice::from_raw_parts::<u8>` with `len == 0`.
+///
+/// This aligns the pointer to `allocation_granularity()` or 1 if unknown.
+fn empty_slice_ptr() -> *mut c_void {
+    let align = allocation_granularity().max(1);
+    unsafe { mem::transmute(align) }
+}
+
+pub struct MmapInner {
+    handle: Option<RawHandle>,
+    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(
+        handle: RawHandle,
+        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;
+        if aligned_len == 0 {
+            // `CreateFileMappingW` documents:
+            //
+            // https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingw
+            // > An attempt to map a file with a length of 0 (zero) fails with an error code
+            // > of ERROR_FILE_INVALID. Applications should test for files with a length of 0
+            // > (zero) and reject those files.
+            //
+            // For such files, don’t create a mapping at all and use a marker pointer instead.
+            return Ok(MmapInner {
+                handle: None,
+                ptr: empty_slice_ptr(),
+                len: 0,
+                copy,
+            });
+        }
+
+        unsafe {
+            let mapping = CreateFileMappingW(handle, ptr::null_mut(), protect, 0, 0, ptr::null());
+            if mapping.is_null() {
+                return Err(io::Error::last_os_error());
+            }
+
+            let ptr = MapViewOfFile(
+                mapping,
+                access,
+                (aligned_offset >> 16 >> 16) as DWORD,
+                (aligned_offset & 0xffffffff) as DWORD,
+                aligned_len as SIZE_T,
+            );
+            CloseHandle(mapping);
+            if ptr.is_null() {
+                return Err(io::Error::last_os_error());
+            }
+
+            let mut new_handle = 0 as RawHandle;
+            let cur_proc = GetCurrentProcess();
+            let ok = DuplicateHandle(
+                cur_proc,
+                handle,
+                cur_proc,
+                &mut new_handle,
+                0,
+                0,
+                DUPLICATE_SAME_ACCESS,
+            );
+            if ok == 0 {
+                UnmapViewOfFile(ptr);
+                return Err(io::Error::last_os_error());
+            }
+
+            Ok(MmapInner {
+                handle: Some(new_handle),
+                ptr: ptr.offset(alignment as isize),
+                len: len as usize,
+                copy,
+            })
+        }
+    }
+
+    pub fn map(
+        len: usize,
+        handle: RawHandle,
+        offset: u64,
+        _populate: bool,
+    ) -> io::Result<MmapInner> {
+        let write = protection_supported(handle, PAGE_READWRITE);
+        let exec = protection_supported(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(handle, protection, access, offset, len, false)?;
+        if write || exec {
+            inner.make_read_only()?;
+        }
+        Ok(inner)
+    }
+
+    pub fn map_exec(
+        len: usize,
+        handle: RawHandle,
+        offset: u64,
+        _populate: bool,
+    ) -> io::Result<MmapInner> {
+        let write = protection_supported(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(handle, protection, access, offset, len, false)?;
+        if write {
+            inner.make_exec()?;
+        }
+        Ok(inner)
+    }
+
+    pub fn map_mut(
+        len: usize,
+        handle: RawHandle,
+        offset: u64,
+        _populate: bool,
+    ) -> io::Result<MmapInner> {
+        let exec = protection_supported(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(handle, protection, access, offset, len, false)?;
+        if exec {
+            inner.make_mut()?;
+        }
+        Ok(inner)
+    }
+
+    pub fn map_copy(
+        len: usize,
+        handle: RawHandle,
+        offset: u64,
+        _populate: bool,
+    ) -> io::Result<MmapInner> {
+        let exec = protection_supported(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(handle, protection, access, offset, len, true)?;
+        if exec {
+            inner.make_mut()?;
+        }
+        Ok(inner)
+    }
+
+    pub fn map_copy_read_only(
+        len: usize,
+        handle: RawHandle,
+        offset: u64,
+        _populate: bool,
+    ) -> io::Result<MmapInner> {
+        let write = protection_supported(handle, PAGE_READWRITE);
+        let exec = protection_supported(handle, PAGE_EXECUTE_READ);
+        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(handle, protection, access, offset, len, true)?;
+        if write || exec {
+            inner.make_read_only()?;
+        }
+        Ok(inner)
+    }
+
+    pub fn map_anon(len: usize, _stack: bool, _populate: bool) -> io::Result<MmapInner> {
+        // Ensure a non-zero length for the underlying mapping
+        let mapped_len = len.max(1);
+        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 mapping = CreateFileMappingW(
+                INVALID_HANDLE_VALUE,
+                ptr::null_mut(),
+                PAGE_EXECUTE_READWRITE,
+                (mapped_len >> 16 >> 16) as DWORD,
+                (mapped_len & 0xffffffff) as DWORD,
+                ptr::null(),
+            );
+            if mapping.is_null() {
+                return Err(io::Error::last_os_error());
+            }
+            let access = FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE;
+            let ptr = MapViewOfFile(mapping, access, 0, 0, mapped_len as SIZE_T);
+            CloseHandle(mapping);
+
+            if ptr.is_null() {
+                return Err(io::Error::last_os_error());
+            }
+
+            let mut old = 0;
+            let result = VirtualProtect(ptr, mapped_len as SIZE_T, PAGE_READWRITE, &mut old);
+            if result != 0 {
+                Ok(MmapInner {
+                    handle: None,
+                    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(handle) = self.handle {
+            let ok = unsafe { FlushFileBuffers(handle) };
+            if ok == 0 {
+                return Err(io::Error::last_os_error());
+            }
+        }
+
+        Ok(())
+    }
+
+    pub fn flush_async(&self, offset: usize, len: usize) -> io::Result<()> {
+        if self.ptr == empty_slice_ptr() {
+            return Ok(());
+        }
+        let result = unsafe { FlushViewOfFile(self.ptr.add(offset), len as SIZE_T) };
+        if result != 0 {
+            Ok(())
+        } else {
+            Err(io::Error::last_os_error())
+        }
+    }
+
+    fn virtual_protect(&mut self, protect: DWORD) -> io::Result<()> {
+        if self.ptr == empty_slice_ptr() {
+            return Ok(());
+        }
+        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) {
+        if self.ptr == empty_slice_ptr() {
+            return;
+        }
+        let alignment = self.ptr as usize % allocation_granularity();
+        // Any errors during unmapping/closing are ignored as the only way
+        // to report them would be through panicking which is highly discouraged
+        // in Drop impls, c.f. https://github.com/rust-lang/lang-team/issues/97
+        unsafe {
+            let ptr = self.ptr.offset(-(alignment as isize));
+            UnmapViewOfFile(ptr);
+
+            if let Some(handle) = self.handle {
+                CloseHandle(handle);
+            }
+        }
+    }
+}
+
+unsafe impl Sync for MmapInner {}
+unsafe impl Send for MmapInner {}
+
+fn protection_supported(handle: RawHandle, protection: DWORD) -> bool {
+    unsafe {
+        let mapping = CreateFileMappingW(handle, ptr::null_mut(), protection, 0, 0, ptr::null());
+        if mapping.is_null() {
+            return false;
+        }
+        CloseHandle(mapping);
+        true
+    }
+}
+
+fn allocation_granularity() -> usize {
+    unsafe {
+        let mut info = mem::zeroed();
+        GetSystemInfo(&mut info);
+        info.dwAllocationGranularity as usize
+    }
+}
+
+pub fn file_len(handle: RawHandle) -> io::Result<u64> {
+    // SAFETY: We must not close the passed-in fd by dropping the File we create,
+    // we ensure this by immediately wrapping it in a ManuallyDrop.
+    unsafe {
+        let file = ManuallyDrop::new(File::from_raw_handle(handle));
+        Ok(file.metadata()?.len())
+    }
+}