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