1 //! A cross-platform Rust API for memory mapped buffers. 2 3 #[cfg(windows)] 4 mod windows; 5 #[cfg(windows)] 6 use crate::windows::file_len; 7 #[cfg(windows)] 8 use crate::windows::MmapInner; 9 10 #[cfg(unix)] 11 mod unix; 12 #[cfg(unix)] 13 use crate::unix::file_len; 14 #[cfg(unix)] 15 use crate::unix::MmapInner; 16 17 #[cfg(not(any(unix, windows)))] 18 mod stub; 19 #[cfg(not(any(unix, windows)))] 20 use crate::stub::file_len; 21 #[cfg(not(any(unix, windows)))] 22 use crate::stub::MmapInner; 23 24 use std::fmt; 25 #[cfg(not(any(unix, windows)))] 26 use std::fs::File; 27 use std::io::{Error, ErrorKind, Result}; 28 use std::ops::{Deref, DerefMut}; 29 #[cfg(unix)] 30 use std::os::unix::io::{AsRawFd, RawFd}; 31 #[cfg(windows)] 32 use std::os::windows::io::{AsRawHandle, RawHandle}; 33 use std::slice; 34 use std::usize; 35 36 #[cfg(not(any(unix, windows)))] 37 pub struct MmapRawDescriptor<'a>(&'a File); 38 39 #[cfg(unix)] 40 pub struct MmapRawDescriptor(RawFd); 41 42 #[cfg(windows)] 43 pub struct MmapRawDescriptor(RawHandle); 44 45 pub trait MmapAsRawDesc { as_raw_desc(&self) -> MmapRawDescriptor46 fn as_raw_desc(&self) -> MmapRawDescriptor; 47 } 48 49 #[cfg(not(any(unix, windows)))] 50 impl MmapAsRawDesc for &File { as_raw_desc(&self) -> MmapRawDescriptor51 fn as_raw_desc(&self) -> MmapRawDescriptor { 52 MmapRawDescriptor(self) 53 } 54 } 55 56 #[cfg(unix)] 57 impl MmapAsRawDesc for RawFd { as_raw_desc(&self) -> MmapRawDescriptor58 fn as_raw_desc(&self) -> MmapRawDescriptor { 59 MmapRawDescriptor(*self) 60 } 61 } 62 63 #[cfg(unix)] 64 impl<'a, T> MmapAsRawDesc for &'a T 65 where 66 T: AsRawFd, 67 { as_raw_desc(&self) -> MmapRawDescriptor68 fn as_raw_desc(&self) -> MmapRawDescriptor { 69 MmapRawDescriptor(self.as_raw_fd()) 70 } 71 } 72 73 #[cfg(windows)] 74 impl MmapAsRawDesc for RawHandle { as_raw_desc(&self) -> MmapRawDescriptor75 fn as_raw_desc(&self) -> MmapRawDescriptor { 76 MmapRawDescriptor(*self) 77 } 78 } 79 80 #[cfg(windows)] 81 impl<'a, T> MmapAsRawDesc for &'a T 82 where 83 T: AsRawHandle, 84 { as_raw_desc(&self) -> MmapRawDescriptor85 fn as_raw_desc(&self) -> MmapRawDescriptor { 86 MmapRawDescriptor(self.as_raw_handle()) 87 } 88 } 89 90 /// A memory map builder, providing advanced options and flags for specifying memory map behavior. 91 /// 92 /// `MmapOptions` can be used to create an anonymous memory map using [`map_anon()`], or a 93 /// file-backed memory map using one of [`map()`], [`map_mut()`], [`map_exec()`], 94 /// [`map_copy()`], or [`map_copy_read_only()`]. 95 /// 96 /// ## Safety 97 /// 98 /// All file-backed memory map constructors are marked `unsafe` because of the potential for 99 /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or 100 /// out of process. Applications must consider the risk and take appropriate precautions when 101 /// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g. 102 /// unlinked) files exist but are platform specific and limited. 103 /// 104 /// [`map_anon()`]: MmapOptions::map_anon() 105 /// [`map()`]: MmapOptions::map() 106 /// [`map_mut()`]: MmapOptions::map_mut() 107 /// [`map_exec()`]: MmapOptions::map_exec() 108 /// [`map_copy()`]: MmapOptions::map_copy() 109 /// [`map_copy_read_only()`]: MmapOptions::map_copy_read_only() 110 #[derive(Clone, Debug, Default)] 111 pub struct MmapOptions { 112 offset: u64, 113 len: Option<usize>, 114 stack: bool, 115 populate: bool, 116 } 117 118 impl MmapOptions { 119 /// Creates a new set of options for configuring and creating a memory map. 120 /// 121 /// # Example 122 /// 123 /// ``` 124 /// use memmap2::{MmapMut, MmapOptions}; 125 /// # use std::io::Result; 126 /// 127 /// # fn main() -> Result<()> { 128 /// // Create a new memory map builder. 129 /// let mut mmap_options = MmapOptions::new(); 130 /// 131 /// // Configure the memory map builder using option setters, then create 132 /// // a memory map using one of `mmap_options.map_anon`, `mmap_options.map`, 133 /// // `mmap_options.map_mut`, `mmap_options.map_exec`, or `mmap_options.map_copy`: 134 /// let mut mmap: MmapMut = mmap_options.len(36).map_anon()?; 135 /// 136 /// // Use the memory map: 137 /// mmap.copy_from_slice(b"...data to copy to the memory map..."); 138 /// # Ok(()) 139 /// # } 140 /// ``` new() -> MmapOptions141 pub fn new() -> MmapOptions { 142 MmapOptions::default() 143 } 144 145 /// Configures the memory map to start at byte `offset` from the beginning of the file. 146 /// 147 /// This option has no effect on anonymous memory maps. 148 /// 149 /// By default, the offset is 0. 150 /// 151 /// # Example 152 /// 153 /// ``` 154 /// use memmap2::MmapOptions; 155 /// use std::fs::File; 156 /// 157 /// # fn main() -> std::io::Result<()> { 158 /// let mmap = unsafe { 159 /// MmapOptions::new() 160 /// .offset(30) 161 /// .map(&File::open("LICENSE-APACHE")?)? 162 /// }; 163 /// assert_eq!(&b"Apache License"[..], 164 /// &mmap[..14]); 165 /// # Ok(()) 166 /// # } 167 /// ``` offset(&mut self, offset: u64) -> &mut Self168 pub fn offset(&mut self, offset: u64) -> &mut Self { 169 self.offset = offset; 170 self 171 } 172 173 /// Configures the created memory mapped buffer to be `len` bytes long. 174 /// 175 /// This option is mandatory for anonymous memory maps. 176 /// 177 /// For file-backed memory maps, the length will default to the file length. 178 /// 179 /// # Example 180 /// 181 /// ``` 182 /// use memmap2::MmapOptions; 183 /// use std::fs::File; 184 /// 185 /// # fn main() -> std::io::Result<()> { 186 /// let mmap = unsafe { 187 /// MmapOptions::new() 188 /// .len(9) 189 /// .map(&File::open("README.md")?)? 190 /// }; 191 /// assert_eq!(&b"# memmap2"[..], &mmap[..]); 192 /// # Ok(()) 193 /// # } 194 /// ``` len(&mut self, len: usize) -> &mut Self195 pub fn len(&mut self, len: usize) -> &mut Self { 196 self.len = Some(len); 197 self 198 } 199 200 /// Returns the configured length, or the length of the provided file. get_len<T: MmapAsRawDesc>(&self, file: &T) -> Result<usize>201 fn get_len<T: MmapAsRawDesc>(&self, file: &T) -> Result<usize> { 202 self.len.map(Ok).unwrap_or_else(|| { 203 let desc = file.as_raw_desc(); 204 let file_len = file_len(desc.0)?; 205 206 if file_len < self.offset { 207 return Err(Error::new( 208 ErrorKind::InvalidData, 209 "memory map offset is larger than length", 210 )); 211 } 212 let len = file_len - self.offset; 213 214 // This check it not relevant on 64bit targets, because usize == u64 215 #[cfg(not(target_pointer_width = "64"))] 216 { 217 if len > (usize::MAX as u64) { 218 return Err(Error::new( 219 ErrorKind::InvalidData, 220 "memory map length overflows usize", 221 )); 222 } 223 } 224 225 Ok(len as usize) 226 }) 227 } 228 229 /// Configures the anonymous memory map to be suitable for a process or thread stack. 230 /// 231 /// This option corresponds to the `MAP_STACK` flag on Linux. It has no effect on Windows. 232 /// 233 /// This option has no effect on file-backed memory maps. 234 /// 235 /// # Example 236 /// 237 /// ``` 238 /// use memmap2::MmapOptions; 239 /// 240 /// # fn main() -> std::io::Result<()> { 241 /// let stack = MmapOptions::new().stack().len(4096).map_anon(); 242 /// # Ok(()) 243 /// # } 244 /// ``` stack(&mut self) -> &mut Self245 pub fn stack(&mut self) -> &mut Self { 246 self.stack = true; 247 self 248 } 249 250 /// Populate (prefault) page tables for a mapping. 251 /// 252 /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later. 253 /// 254 /// This option corresponds to the `MAP_POPULATE` flag on Linux. It has no effect on Windows. 255 /// 256 /// # Example 257 /// 258 /// ``` 259 /// use memmap2::MmapOptions; 260 /// use std::fs::File; 261 /// 262 /// # fn main() -> std::io::Result<()> { 263 /// let file = File::open("LICENSE-MIT")?; 264 /// 265 /// let mmap = unsafe { 266 /// MmapOptions::new().populate().map(&file)? 267 /// }; 268 /// 269 /// assert_eq!(&b"Copyright"[..], &mmap[..9]); 270 /// # Ok(()) 271 /// # } 272 /// ``` populate(&mut self) -> &mut Self273 pub fn populate(&mut self) -> &mut Self { 274 self.populate = true; 275 self 276 } 277 278 /// Creates a read-only memory map backed by a file. 279 /// 280 /// # Errors 281 /// 282 /// This method returns an error when the underlying system call fails, which can happen for a 283 /// variety of reasons, such as when the file is not open with read permissions. 284 /// 285 /// # Example 286 /// 287 /// ``` 288 /// use memmap2::MmapOptions; 289 /// use std::fs::File; 290 /// use std::io::Read; 291 /// 292 /// # fn main() -> std::io::Result<()> { 293 /// let mut file = File::open("LICENSE-APACHE")?; 294 /// 295 /// let mut contents = Vec::new(); 296 /// file.read_to_end(&mut contents)?; 297 /// 298 /// let mmap = unsafe { 299 /// MmapOptions::new().map(&file)? 300 /// }; 301 /// 302 /// assert_eq!(&contents[..], &mmap[..]); 303 /// # Ok(()) 304 /// # } 305 /// ``` map<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap>306 pub unsafe fn map<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> { 307 let desc = file.as_raw_desc(); 308 309 MmapInner::map(self.get_len(&file)?, desc.0, self.offset, self.populate) 310 .map(|inner| Mmap { inner }) 311 } 312 313 /// Creates a readable and executable memory map backed by a file. 314 /// 315 /// # Errors 316 /// 317 /// This method returns an error when the underlying system call fails, which can happen for a 318 /// variety of reasons, such as when the file is not open with read permissions. map_exec<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap>319 pub unsafe fn map_exec<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> { 320 let desc = file.as_raw_desc(); 321 322 MmapInner::map_exec(self.get_len(&file)?, desc.0, self.offset, self.populate) 323 .map(|inner| Mmap { inner }) 324 } 325 326 /// Creates a writeable memory map backed by a file. 327 /// 328 /// # Errors 329 /// 330 /// This method returns an error when the underlying system call fails, which can happen for a 331 /// variety of reasons, such as when the file is not open with read and write permissions. 332 /// 333 /// # Example 334 /// 335 /// ``` 336 /// # extern crate memmap2; 337 /// # extern crate tempdir; 338 /// # 339 /// use std::fs::OpenOptions; 340 /// use std::path::PathBuf; 341 /// 342 /// use memmap2::MmapOptions; 343 /// # 344 /// # fn main() -> std::io::Result<()> { 345 /// # let tempdir = tempdir::TempDir::new("mmap")?; 346 /// let path: PathBuf = /* path to file */ 347 /// # tempdir.path().join("map_mut"); 348 /// let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?; 349 /// file.set_len(13)?; 350 /// 351 /// let mut mmap = unsafe { 352 /// MmapOptions::new().map_mut(&file)? 353 /// }; 354 /// 355 /// mmap.copy_from_slice(b"Hello, world!"); 356 /// # Ok(()) 357 /// # } 358 /// ``` map_mut<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut>359 pub unsafe fn map_mut<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut> { 360 let desc = file.as_raw_desc(); 361 362 MmapInner::map_mut(self.get_len(&file)?, desc.0, self.offset, self.populate) 363 .map(|inner| MmapMut { inner }) 364 } 365 366 /// Creates a copy-on-write memory map backed by a file. 367 /// 368 /// Data written to the memory map will not be visible by other processes, 369 /// and will not be carried through to the underlying file. 370 /// 371 /// # Errors 372 /// 373 /// This method returns an error when the underlying system call fails, which can happen for a 374 /// variety of reasons, such as when the file is not open with writable permissions. 375 /// 376 /// # Example 377 /// 378 /// ``` 379 /// use memmap2::MmapOptions; 380 /// use std::fs::File; 381 /// use std::io::Write; 382 /// 383 /// # fn main() -> std::io::Result<()> { 384 /// let file = File::open("LICENSE-APACHE")?; 385 /// let mut mmap = unsafe { MmapOptions::new().map_copy(&file)? }; 386 /// (&mut mmap[..]).write_all(b"Hello, world!")?; 387 /// # Ok(()) 388 /// # } 389 /// ``` map_copy<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut>390 pub unsafe fn map_copy<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut> { 391 let desc = file.as_raw_desc(); 392 393 MmapInner::map_copy(self.get_len(&file)?, desc.0, self.offset, self.populate) 394 .map(|inner| MmapMut { inner }) 395 } 396 397 /// Creates a copy-on-write read-only memory map backed by a file. 398 /// 399 /// # Errors 400 /// 401 /// This method returns an error when the underlying system call fails, which can happen for a 402 /// variety of reasons, such as when the file is not open with read permissions. 403 /// 404 /// # Example 405 /// 406 /// ``` 407 /// use memmap2::MmapOptions; 408 /// use std::fs::File; 409 /// use std::io::Read; 410 /// 411 /// # fn main() -> std::io::Result<()> { 412 /// let mut file = File::open("README.md")?; 413 /// 414 /// let mut contents = Vec::new(); 415 /// file.read_to_end(&mut contents)?; 416 /// 417 /// let mmap = unsafe { 418 /// MmapOptions::new().map_copy_read_only(&file)? 419 /// }; 420 /// 421 /// assert_eq!(&contents[..], &mmap[..]); 422 /// # Ok(()) 423 /// # } 424 /// ``` map_copy_read_only<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap>425 pub unsafe fn map_copy_read_only<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> { 426 let desc = file.as_raw_desc(); 427 428 MmapInner::map_copy_read_only(self.get_len(&file)?, desc.0, self.offset, self.populate) 429 .map(|inner| Mmap { inner }) 430 } 431 432 /// Creates an anonymous memory map. 433 /// 434 /// Note: the memory map length must be configured to be greater than 0 before creating an 435 /// anonymous memory map using `MmapOptions::len()`. 436 /// 437 /// # Errors 438 /// 439 /// This method returns an error when the underlying system call fails. map_anon(&self) -> Result<MmapMut>440 pub fn map_anon(&self) -> Result<MmapMut> { 441 MmapInner::map_anon(self.len.unwrap_or(0), self.stack).map(|inner| MmapMut { inner }) 442 } 443 444 /// Creates a raw memory map. 445 /// 446 /// # Errors 447 /// 448 /// This method returns an error when the underlying system call fails, which can happen for a 449 /// variety of reasons, such as when the file is not open with read and write permissions. map_raw<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapRaw>450 pub fn map_raw<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapRaw> { 451 let desc = file.as_raw_desc(); 452 453 MmapInner::map_mut(self.get_len(&file)?, desc.0, self.offset, self.populate) 454 .map(|inner| MmapRaw { inner }) 455 } 456 } 457 458 /// A handle to an immutable memory mapped buffer. 459 /// 460 /// A `Mmap` may be backed by a file, or it can be anonymous map, backed by volatile memory. Use 461 /// [`MmapOptions`] or [`map()`] to create a file-backed memory map. To create an immutable 462 /// anonymous memory map, first create a mutable anonymous memory map, and then make it immutable 463 /// with [`MmapMut::make_read_only()`]. 464 /// 465 /// A file backed `Mmap` is created by `&File` reference, and will remain valid even after the 466 /// `File` is dropped. In other words, the `Mmap` handle is completely independent of the `File` 467 /// used to create it. For consistency, on some platforms this is achieved by duplicating the 468 /// underlying file handle. The memory will be unmapped when the `Mmap` handle is dropped. 469 /// 470 /// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping 471 /// the mapped pages into physical memory) though the details of this are platform specific. 472 /// 473 /// `Mmap` is [`Sync`](std::marker::Sync) and [`Send`](std::marker::Send). 474 /// 475 /// ## Safety 476 /// 477 /// All file-backed memory map constructors are marked `unsafe` because of the potential for 478 /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or 479 /// out of process. Applications must consider the risk and take appropriate precautions when using 480 /// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked) 481 /// files exist but are platform specific and limited. 482 /// 483 /// ## Example 484 /// 485 /// ``` 486 /// use memmap2::MmapOptions; 487 /// use std::io::Write; 488 /// use std::fs::File; 489 /// 490 /// # fn main() -> std::io::Result<()> { 491 /// let file = File::open("README.md")?; 492 /// let mmap = unsafe { MmapOptions::new().map(&file)? }; 493 /// assert_eq!(b"# memmap2", &mmap[0..9]); 494 /// # Ok(()) 495 /// # } 496 /// ``` 497 /// 498 /// See [`MmapMut`] for the mutable version. 499 /// 500 /// [`map()`]: Mmap::map() 501 pub struct Mmap { 502 inner: MmapInner, 503 } 504 505 impl Mmap { 506 /// Creates a read-only memory map backed by a file. 507 /// 508 /// This is equivalent to calling `MmapOptions::new().map(file)`. 509 /// 510 /// # Errors 511 /// 512 /// This method returns an error when the underlying system call fails, which can happen for a 513 /// variety of reasons, such as when the file is not open with read permissions. 514 /// 515 /// # Example 516 /// 517 /// ``` 518 /// use std::fs::File; 519 /// use std::io::Read; 520 /// 521 /// use memmap2::Mmap; 522 /// 523 /// # fn main() -> std::io::Result<()> { 524 /// let mut file = File::open("LICENSE-APACHE")?; 525 /// 526 /// let mut contents = Vec::new(); 527 /// file.read_to_end(&mut contents)?; 528 /// 529 /// let mmap = unsafe { Mmap::map(&file)? }; 530 /// 531 /// assert_eq!(&contents[..], &mmap[..]); 532 /// # Ok(()) 533 /// # } 534 /// ``` map<T: MmapAsRawDesc>(file: T) -> Result<Mmap>535 pub unsafe fn map<T: MmapAsRawDesc>(file: T) -> Result<Mmap> { 536 MmapOptions::new().map(file) 537 } 538 539 /// Transition the memory map to be writable. 540 /// 541 /// If the memory map is file-backed, the file must have been opened with write permissions. 542 /// 543 /// # Errors 544 /// 545 /// This method returns an error when the underlying system call fails, which can happen for a 546 /// variety of reasons, such as when the file is not open with writable permissions. 547 /// 548 /// # Example 549 /// 550 /// ``` 551 /// # extern crate memmap2; 552 /// # extern crate tempdir; 553 /// # 554 /// use memmap2::Mmap; 555 /// use std::ops::DerefMut; 556 /// use std::io::Write; 557 /// # use std::fs::OpenOptions; 558 /// 559 /// # fn main() -> std::io::Result<()> { 560 /// # let tempdir = tempdir::TempDir::new("mmap")?; 561 /// let file = /* file opened with write permissions */ 562 /// # OpenOptions::new() 563 /// # .read(true) 564 /// # .write(true) 565 /// # .create(true) 566 /// # .open(tempdir.path() 567 /// # .join("make_mut"))?; 568 /// # file.set_len(128)?; 569 /// let mmap = unsafe { Mmap::map(&file)? }; 570 /// // ... use the read-only memory map ... 571 /// let mut mut_mmap = mmap.make_mut()?; 572 /// mut_mmap.deref_mut().write_all(b"hello, world!")?; 573 /// # Ok(()) 574 /// # } 575 /// ``` make_mut(mut self) -> Result<MmapMut>576 pub fn make_mut(mut self) -> Result<MmapMut> { 577 self.inner.make_mut()?; 578 Ok(MmapMut { inner: self.inner }) 579 } 580 } 581 582 #[cfg(feature = "stable_deref_trait")] 583 unsafe impl stable_deref_trait::StableDeref for Mmap {} 584 585 impl Deref for Mmap { 586 type Target = [u8]; 587 588 #[inline] deref(&self) -> &[u8]589 fn deref(&self) -> &[u8] { 590 unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) } 591 } 592 } 593 594 impl AsRef<[u8]> for Mmap { 595 #[inline] as_ref(&self) -> &[u8]596 fn as_ref(&self) -> &[u8] { 597 self.deref() 598 } 599 } 600 601 impl fmt::Debug for Mmap { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result602 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 603 fmt.debug_struct("Mmap") 604 .field("ptr", &self.as_ptr()) 605 .field("len", &self.len()) 606 .finish() 607 } 608 } 609 610 /// A handle to a raw memory mapped buffer. 611 /// 612 /// This struct never hands out references to its interior, only raw pointers. 613 /// This can be helpful when creating shared memory maps between untrusted processes. 614 pub struct MmapRaw { 615 inner: MmapInner, 616 } 617 618 impl MmapRaw { 619 /// Creates a writeable memory map backed by a file. 620 /// 621 /// This is equivalent to calling `MmapOptions::new().map_raw(file)`. 622 /// 623 /// # Errors 624 /// 625 /// This method returns an error when the underlying system call fails, which can happen for a 626 /// variety of reasons, such as when the file is not open with read and write permissions. map_raw<T: MmapAsRawDesc>(file: T) -> Result<MmapRaw>627 pub fn map_raw<T: MmapAsRawDesc>(file: T) -> Result<MmapRaw> { 628 MmapOptions::new().map_raw(file) 629 } 630 631 /// Returns a raw pointer to the memory mapped file. 632 /// 633 /// Before dereferencing this pointer, you have to make sure that the file has not been 634 /// truncated since the memory map was created. 635 /// Avoiding this will not introduce memory safety issues in Rust terms, 636 /// but will cause SIGBUS (or equivalent) signal. 637 #[inline] as_ptr(&self) -> *const u8638 pub fn as_ptr(&self) -> *const u8 { 639 self.inner.ptr() 640 } 641 642 /// Returns an unsafe mutable pointer to the memory mapped file. 643 /// 644 /// Before dereferencing this pointer, you have to make sure that the file has not been 645 /// truncated since the memory map was created. 646 /// Avoiding this will not introduce memory safety issues in Rust terms, 647 /// but will cause SIGBUS (or equivalent) signal. 648 #[inline] as_mut_ptr(&self) -> *mut u8649 pub fn as_mut_ptr(&self) -> *mut u8 { 650 self.inner.ptr() as _ 651 } 652 653 /// Returns the length in bytes of the memory map. 654 /// 655 /// Note that truncating the file can cause the length to change (and render this value unusable). 656 #[inline] len(&self) -> usize657 pub fn len(&self) -> usize { 658 self.inner.len() 659 } 660 } 661 662 impl fmt::Debug for MmapRaw { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result663 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 664 fmt.debug_struct("MmapRaw") 665 .field("ptr", &self.as_ptr()) 666 .field("len", &self.len()) 667 .finish() 668 } 669 } 670 671 /// A handle to a mutable memory mapped buffer. 672 /// 673 /// A file-backed `MmapMut` buffer may be used to read from or write to a file. An anonymous 674 /// `MmapMut` buffer may be used any place that an in-memory byte buffer is needed. Use 675 /// [`MmapMut::map_mut()`] and [`MmapMut::map_anon()`] to create a mutable memory map of the 676 /// respective types, or [`MmapOptions::map_mut()`] and [`MmapOptions::map_anon()`] if non-default 677 /// options are required. 678 /// 679 /// A file backed `MmapMut` is created by `&File` reference, and will remain valid even after the 680 /// `File` is dropped. In other words, the `MmapMut` handle is completely independent of the `File` 681 /// used to create it. For consistency, on some platforms this is achieved by duplicating the 682 /// underlying file handle. The memory will be unmapped when the `MmapMut` handle is dropped. 683 /// 684 /// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping 685 /// the mapped pages into physical memory) though the details of this are platform specific. 686 /// 687 /// `Mmap` is [`Sync`](std::marker::Sync) and [`Send`](std::marker::Send). 688 /// 689 /// See [`Mmap`] for the immutable version. 690 /// 691 /// ## Safety 692 /// 693 /// All file-backed memory map constructors are marked `unsafe` because of the potential for 694 /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or 695 /// out of process. Applications must consider the risk and take appropriate precautions when using 696 /// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked) 697 /// files exist but are platform specific and limited. 698 pub struct MmapMut { 699 inner: MmapInner, 700 } 701 702 impl MmapMut { 703 /// Creates a writeable memory map backed by a file. 704 /// 705 /// This is equivalent to calling `MmapOptions::new().map_mut(file)`. 706 /// 707 /// # Errors 708 /// 709 /// This method returns an error when the underlying system call fails, which can happen for a 710 /// variety of reasons, such as when the file is not open with read and write permissions. 711 /// 712 /// # Example 713 /// 714 /// ``` 715 /// # extern crate memmap2; 716 /// # extern crate tempdir; 717 /// # 718 /// use std::fs::OpenOptions; 719 /// use std::path::PathBuf; 720 /// 721 /// use memmap2::MmapMut; 722 /// # 723 /// # fn main() -> std::io::Result<()> { 724 /// # let tempdir = tempdir::TempDir::new("mmap")?; 725 /// let path: PathBuf = /* path to file */ 726 /// # tempdir.path().join("map_mut"); 727 /// let file = OpenOptions::new() 728 /// .read(true) 729 /// .write(true) 730 /// .create(true) 731 /// .open(&path)?; 732 /// file.set_len(13)?; 733 /// 734 /// let mut mmap = unsafe { MmapMut::map_mut(&file)? }; 735 /// 736 /// mmap.copy_from_slice(b"Hello, world!"); 737 /// # Ok(()) 738 /// # } 739 /// ``` map_mut<T: MmapAsRawDesc>(file: T) -> Result<MmapMut>740 pub unsafe fn map_mut<T: MmapAsRawDesc>(file: T) -> Result<MmapMut> { 741 MmapOptions::new().map_mut(file) 742 } 743 744 /// Creates an anonymous memory map. 745 /// 746 /// This is equivalent to calling `MmapOptions::new().len(length).map_anon()`. 747 /// 748 /// # Errors 749 /// 750 /// This method returns an error when the underlying system call fails. map_anon(length: usize) -> Result<MmapMut>751 pub fn map_anon(length: usize) -> Result<MmapMut> { 752 MmapOptions::new().len(length).map_anon() 753 } 754 755 /// Flushes outstanding memory map modifications to disk. 756 /// 757 /// When this method returns with a non-error result, all outstanding changes to a file-backed 758 /// memory map are guaranteed to be durably stored. The file's metadata (including last 759 /// modification timestamp) may not be updated. 760 /// 761 /// # Example 762 /// 763 /// ``` 764 /// # extern crate memmap2; 765 /// # extern crate tempdir; 766 /// # 767 /// use std::fs::OpenOptions; 768 /// use std::io::Write; 769 /// use std::path::PathBuf; 770 /// 771 /// use memmap2::MmapMut; 772 /// 773 /// # fn main() -> std::io::Result<()> { 774 /// # let tempdir = tempdir::TempDir::new("mmap")?; 775 /// let path: PathBuf = /* path to file */ 776 /// # tempdir.path().join("flush"); 777 /// let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?; 778 /// file.set_len(128)?; 779 /// 780 /// let mut mmap = unsafe { MmapMut::map_mut(&file)? }; 781 /// 782 /// (&mut mmap[..]).write_all(b"Hello, world!")?; 783 /// mmap.flush()?; 784 /// # Ok(()) 785 /// # } 786 /// ``` flush(&self) -> Result<()>787 pub fn flush(&self) -> Result<()> { 788 let len = self.len(); 789 self.inner.flush(0, len) 790 } 791 792 /// Asynchronously flushes outstanding memory map modifications to disk. 793 /// 794 /// This method initiates flushing modified pages to durable storage, but it will not wait for 795 /// the operation to complete before returning. The file's metadata (including last 796 /// modification timestamp) may not be updated. flush_async(&self) -> Result<()>797 pub fn flush_async(&self) -> Result<()> { 798 let len = self.len(); 799 self.inner.flush_async(0, len) 800 } 801 802 /// Flushes outstanding memory map modifications in the range to disk. 803 /// 804 /// The offset and length must be in the bounds of the memory map. 805 /// 806 /// When this method returns with a non-error result, all outstanding changes to a file-backed 807 /// memory in the range are guaranteed to be durable stored. The file's metadata (including 808 /// last modification timestamp) may not be updated. It is not guaranteed the only the changes 809 /// in the specified range are flushed; other outstanding changes to the memory map may be 810 /// flushed as well. flush_range(&self, offset: usize, len: usize) -> Result<()>811 pub fn flush_range(&self, offset: usize, len: usize) -> Result<()> { 812 self.inner.flush(offset, len) 813 } 814 815 /// Asynchronously flushes outstanding memory map modifications in the range to disk. 816 /// 817 /// The offset and length must be in the bounds of the memory map. 818 /// 819 /// This method initiates flushing modified pages to durable storage, but it will not wait for 820 /// the operation to complete before returning. The file's metadata (including last 821 /// modification timestamp) may not be updated. It is not guaranteed that the only changes 822 /// flushed are those in the specified range; other outstanding changes to the memory map may 823 /// be flushed as well. flush_async_range(&self, offset: usize, len: usize) -> Result<()>824 pub fn flush_async_range(&self, offset: usize, len: usize) -> Result<()> { 825 self.inner.flush_async(offset, len) 826 } 827 828 /// Returns an immutable version of this memory mapped buffer. 829 /// 830 /// If the memory map is file-backed, the file must have been opened with read permissions. 831 /// 832 /// # Errors 833 /// 834 /// This method returns an error when the underlying system call fails, which can happen for a 835 /// variety of reasons, such as when the file has not been opened with read permissions. 836 /// 837 /// # Example 838 /// 839 /// ``` 840 /// # extern crate memmap2; 841 /// # 842 /// use std::io::Write; 843 /// use std::path::PathBuf; 844 /// 845 /// use memmap2::{Mmap, MmapMut}; 846 /// 847 /// # fn main() -> std::io::Result<()> { 848 /// let mut mmap = MmapMut::map_anon(128)?; 849 /// 850 /// (&mut mmap[..]).write(b"Hello, world!")?; 851 /// 852 /// let mmap: Mmap = mmap.make_read_only()?; 853 /// # Ok(()) 854 /// # } 855 /// ``` make_read_only(mut self) -> Result<Mmap>856 pub fn make_read_only(mut self) -> Result<Mmap> { 857 self.inner.make_read_only()?; 858 Ok(Mmap { inner: self.inner }) 859 } 860 861 /// Transition the memory map to be readable and executable. 862 /// 863 /// If the memory map is file-backed, the file must have been opened with execute permissions. 864 /// 865 /// # Errors 866 /// 867 /// This method returns an error when the underlying system call fails, which can happen for a 868 /// variety of reasons, such as when the file has not been opened with execute permissions. make_exec(mut self) -> Result<Mmap>869 pub fn make_exec(mut self) -> Result<Mmap> { 870 self.inner.make_exec()?; 871 Ok(Mmap { inner: self.inner }) 872 } 873 } 874 875 #[cfg(feature = "stable_deref_trait")] 876 unsafe impl stable_deref_trait::StableDeref for MmapMut {} 877 878 impl Deref for MmapMut { 879 type Target = [u8]; 880 881 #[inline] deref(&self) -> &[u8]882 fn deref(&self) -> &[u8] { 883 unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) } 884 } 885 } 886 887 impl DerefMut for MmapMut { 888 #[inline] deref_mut(&mut self) -> &mut [u8]889 fn deref_mut(&mut self) -> &mut [u8] { 890 unsafe { slice::from_raw_parts_mut(self.inner.mut_ptr(), self.inner.len()) } 891 } 892 } 893 894 impl AsRef<[u8]> for MmapMut { 895 #[inline] as_ref(&self) -> &[u8]896 fn as_ref(&self) -> &[u8] { 897 self.deref() 898 } 899 } 900 901 impl AsMut<[u8]> for MmapMut { 902 #[inline] as_mut(&mut self) -> &mut [u8]903 fn as_mut(&mut self) -> &mut [u8] { 904 self.deref_mut() 905 } 906 } 907 908 impl fmt::Debug for MmapMut { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result909 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 910 fmt.debug_struct("MmapMut") 911 .field("ptr", &self.as_ptr()) 912 .field("len", &self.len()) 913 .finish() 914 } 915 } 916 917 #[cfg(test)] 918 mod test { 919 extern crate tempdir; 920 921 use std::fs::OpenOptions; 922 use std::io::{Read, Write}; 923 #[cfg(unix)] 924 use std::os::unix::io::AsRawFd; 925 #[cfg(windows)] 926 use std::os::windows::fs::OpenOptionsExt; 927 928 #[cfg(windows)] 929 const GENERIC_ALL: u32 = 0x10000000; 930 931 use super::{Mmap, MmapMut, MmapOptions}; 932 933 #[test] map_file()934 fn map_file() { 935 let expected_len = 128; 936 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 937 let path = tempdir.path().join("mmap"); 938 939 let file = OpenOptions::new() 940 .read(true) 941 .write(true) 942 .create(true) 943 .open(&path) 944 .unwrap(); 945 946 file.set_len(expected_len as u64).unwrap(); 947 948 let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; 949 let len = mmap.len(); 950 assert_eq!(expected_len, len); 951 952 let zeros = vec![0; len]; 953 let incr: Vec<u8> = (0..len as u8).collect(); 954 955 // check that the mmap is empty 956 assert_eq!(&zeros[..], &mmap[..]); 957 958 // write values into the mmap 959 (&mut mmap[..]).write_all(&incr[..]).unwrap(); 960 961 // read values back 962 assert_eq!(&incr[..], &mmap[..]); 963 } 964 965 #[test] 966 #[cfg(unix)] map_fd()967 fn map_fd() { 968 let expected_len = 128; 969 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 970 let path = tempdir.path().join("mmap"); 971 972 let file = OpenOptions::new() 973 .read(true) 974 .write(true) 975 .create(true) 976 .open(&path) 977 .unwrap(); 978 979 file.set_len(expected_len as u64).unwrap(); 980 981 let mut mmap = unsafe { MmapMut::map_mut(file.as_raw_fd()).unwrap() }; 982 let len = mmap.len(); 983 assert_eq!(expected_len, len); 984 985 let zeros = vec![0; len]; 986 let incr: Vec<u8> = (0..len as u8).collect(); 987 988 // check that the mmap is empty 989 assert_eq!(&zeros[..], &mmap[..]); 990 991 // write values into the mmap 992 (&mut mmap[..]).write_all(&incr[..]).unwrap(); 993 994 // read values back 995 assert_eq!(&incr[..], &mmap[..]); 996 } 997 998 /// Checks that "mapping" a 0-length file derefs to an empty slice. 999 #[test] map_empty_file()1000 fn map_empty_file() { 1001 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 1002 let path = tempdir.path().join("mmap"); 1003 1004 let file = OpenOptions::new() 1005 .read(true) 1006 .write(true) 1007 .create(true) 1008 .open(&path) 1009 .unwrap(); 1010 let mmap = unsafe { Mmap::map(&file).unwrap() }; 1011 assert!(mmap.is_empty()); 1012 let mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; 1013 assert!(mmap.is_empty()); 1014 } 1015 1016 #[test] map_anon()1017 fn map_anon() { 1018 let expected_len = 128; 1019 let mut mmap = MmapMut::map_anon(expected_len).unwrap(); 1020 let len = mmap.len(); 1021 assert_eq!(expected_len, len); 1022 1023 let zeros = vec![0; len]; 1024 let incr: Vec<u8> = (0..len as u8).collect(); 1025 1026 // check that the mmap is empty 1027 assert_eq!(&zeros[..], &mmap[..]); 1028 1029 // write values into the mmap 1030 (&mut mmap[..]).write_all(&incr[..]).unwrap(); 1031 1032 // read values back 1033 assert_eq!(&incr[..], &mmap[..]); 1034 } 1035 1036 #[test] map_anon_zero_len()1037 fn map_anon_zero_len() { 1038 assert!(MmapOptions::new().map_anon().unwrap().is_empty()) 1039 } 1040 1041 #[test] file_write()1042 fn file_write() { 1043 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 1044 let path = tempdir.path().join("mmap"); 1045 1046 let mut file = OpenOptions::new() 1047 .read(true) 1048 .write(true) 1049 .create(true) 1050 .open(&path) 1051 .unwrap(); 1052 file.set_len(128).unwrap(); 1053 1054 let write = b"abc123"; 1055 let mut read = [0u8; 6]; 1056 1057 let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; 1058 (&mut mmap[..]).write_all(write).unwrap(); 1059 mmap.flush().unwrap(); 1060 1061 file.read_exact(&mut read).unwrap(); 1062 assert_eq!(write, &read); 1063 } 1064 1065 #[test] flush_range()1066 fn flush_range() { 1067 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 1068 let path = tempdir.path().join("mmap"); 1069 1070 let file = OpenOptions::new() 1071 .read(true) 1072 .write(true) 1073 .create(true) 1074 .open(&path) 1075 .unwrap(); 1076 file.set_len(128).unwrap(); 1077 let write = b"abc123"; 1078 1079 let mut mmap = unsafe { 1080 MmapOptions::new() 1081 .offset(2) 1082 .len(write.len()) 1083 .map_mut(&file) 1084 .unwrap() 1085 }; 1086 (&mut mmap[..]).write_all(write).unwrap(); 1087 mmap.flush_async_range(0, write.len()).unwrap(); 1088 mmap.flush_range(0, write.len()).unwrap(); 1089 } 1090 1091 #[test] map_copy()1092 fn map_copy() { 1093 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 1094 let path = tempdir.path().join("mmap"); 1095 1096 let mut file = OpenOptions::new() 1097 .read(true) 1098 .write(true) 1099 .create(true) 1100 .open(&path) 1101 .unwrap(); 1102 file.set_len(128).unwrap(); 1103 1104 let nulls = b"\0\0\0\0\0\0"; 1105 let write = b"abc123"; 1106 let mut read = [0u8; 6]; 1107 1108 let mut mmap = unsafe { MmapOptions::new().map_copy(&file).unwrap() }; 1109 1110 (&mut mmap[..]).write_all(write).unwrap(); 1111 mmap.flush().unwrap(); 1112 1113 // The mmap contains the write 1114 (&mmap[..]).read_exact(&mut read).unwrap(); 1115 assert_eq!(write, &read); 1116 1117 // The file does not contain the write 1118 file.read_exact(&mut read).unwrap(); 1119 assert_eq!(nulls, &read); 1120 1121 // another mmap does not contain the write 1122 let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; 1123 (&mmap2[..]).read_exact(&mut read).unwrap(); 1124 assert_eq!(nulls, &read); 1125 } 1126 1127 #[test] map_copy_read_only()1128 fn map_copy_read_only() { 1129 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 1130 let path = tempdir.path().join("mmap"); 1131 1132 let file = OpenOptions::new() 1133 .read(true) 1134 .write(true) 1135 .create(true) 1136 .open(&path) 1137 .unwrap(); 1138 file.set_len(128).unwrap(); 1139 1140 let nulls = b"\0\0\0\0\0\0"; 1141 let mut read = [0u8; 6]; 1142 1143 let mmap = unsafe { MmapOptions::new().map_copy_read_only(&file).unwrap() }; 1144 (&mmap[..]).read_exact(&mut read).unwrap(); 1145 assert_eq!(nulls, &read); 1146 1147 let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; 1148 (&mmap2[..]).read_exact(&mut read).unwrap(); 1149 assert_eq!(nulls, &read); 1150 } 1151 1152 // 32bit Linux cannot map a file larger than i32, but Windows can. 1153 #[cfg(all(target_os = "linux", target_pointer_width = "32"))] 1154 #[test] map_offset()1155 fn map_offset() { 1156 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 1157 let path = tempdir.path().join("mmap"); 1158 1159 let file = OpenOptions::new() 1160 .read(true) 1161 .write(true) 1162 .create(true) 1163 .open(&path) 1164 .unwrap(); 1165 1166 let offset = u32::max_value() as u64 + 2; 1167 let len = 5432; 1168 file.set_len(offset + len as u64).unwrap(); 1169 1170 let mmap = unsafe { MmapOptions::new().offset(offset).map_mut(&file) }; 1171 assert!(mmap.is_err()); 1172 } 1173 1174 #[cfg(not(all(target_os = "linux", target_pointer_width = "32")))] 1175 #[test] map_offset()1176 fn map_offset() { 1177 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 1178 let path = tempdir.path().join("mmap"); 1179 1180 let file = OpenOptions::new() 1181 .read(true) 1182 .write(true) 1183 .create(true) 1184 .open(&path) 1185 .unwrap(); 1186 1187 let offset = u32::max_value() as u64 + 2; 1188 let len = 5432; 1189 file.set_len(offset + len as u64).unwrap(); 1190 1191 // Check inferred length mmap. 1192 let mmap = unsafe { MmapOptions::new().offset(offset).map_mut(&file).unwrap() }; 1193 assert_eq!(len, mmap.len()); 1194 1195 // Check explicit length mmap. 1196 let mut mmap = unsafe { 1197 MmapOptions::new() 1198 .offset(offset) 1199 .len(len) 1200 .map_mut(&file) 1201 .unwrap() 1202 }; 1203 assert_eq!(len, mmap.len()); 1204 1205 let zeros = vec![0; len]; 1206 let incr: Vec<_> = (0..len).map(|i| i as u8).collect(); 1207 1208 // check that the mmap is empty 1209 assert_eq!(&zeros[..], &mmap[..]); 1210 1211 // write values into the mmap 1212 (&mut mmap[..]).write_all(&incr[..]).unwrap(); 1213 1214 // read values back 1215 assert_eq!(&incr[..], &mmap[..]); 1216 } 1217 1218 #[test] index()1219 fn index() { 1220 let mut mmap = MmapMut::map_anon(128).unwrap(); 1221 mmap[0] = 42; 1222 assert_eq!(42, mmap[0]); 1223 } 1224 1225 #[test] sync_send()1226 fn sync_send() { 1227 let mmap = MmapMut::map_anon(129).unwrap(); 1228 1229 fn is_sync_send<T>(_val: T) 1230 where 1231 T: Sync + Send, 1232 { 1233 } 1234 1235 is_sync_send(mmap); 1236 } 1237 1238 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] jit_x86(mut mmap: MmapMut)1239 fn jit_x86(mut mmap: MmapMut) { 1240 use std::mem; 1241 mmap[0] = 0xB8; // mov eax, 0xAB 1242 mmap[1] = 0xAB; 1243 mmap[2] = 0x00; 1244 mmap[3] = 0x00; 1245 mmap[4] = 0x00; 1246 mmap[5] = 0xC3; // ret 1247 1248 let mmap = mmap.make_exec().expect("make_exec"); 1249 1250 let jitfn: extern "C" fn() -> u8 = unsafe { mem::transmute(mmap.as_ptr()) }; 1251 assert_eq!(jitfn(), 0xab); 1252 } 1253 1254 #[test] 1255 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] jit_x86_anon()1256 fn jit_x86_anon() { 1257 jit_x86(MmapMut::map_anon(4096).unwrap()); 1258 } 1259 1260 #[test] 1261 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] jit_x86_file()1262 fn jit_x86_file() { 1263 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 1264 let mut options = OpenOptions::new(); 1265 #[cfg(windows)] 1266 options.access_mode(GENERIC_ALL); 1267 1268 let file = options 1269 .read(true) 1270 .write(true) 1271 .create(true) 1272 .open(&tempdir.path().join("jit_x86")) 1273 .expect("open"); 1274 1275 file.set_len(4096).expect("set_len"); 1276 jit_x86(unsafe { MmapMut::map_mut(&file).expect("map_mut") }); 1277 } 1278 1279 #[test] mprotect_file()1280 fn mprotect_file() { 1281 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 1282 let path = tempdir.path().join("mmap"); 1283 1284 let mut options = OpenOptions::new(); 1285 #[cfg(windows)] 1286 options.access_mode(GENERIC_ALL); 1287 1288 let mut file = options 1289 .read(true) 1290 .write(true) 1291 .create(true) 1292 .open(&path) 1293 .expect("open"); 1294 file.set_len(256_u64).expect("set_len"); 1295 1296 let mmap = unsafe { MmapMut::map_mut(&file).expect("map_mut") }; 1297 1298 let mmap = mmap.make_read_only().expect("make_read_only"); 1299 let mut mmap = mmap.make_mut().expect("make_mut"); 1300 1301 let write = b"abc123"; 1302 let mut read = [0u8; 6]; 1303 1304 (&mut mmap[..]).write_all(write).unwrap(); 1305 mmap.flush().unwrap(); 1306 1307 // The mmap contains the write 1308 (&mmap[..]).read_exact(&mut read).unwrap(); 1309 assert_eq!(write, &read); 1310 1311 // The file should contain the write 1312 file.read_exact(&mut read).unwrap(); 1313 assert_eq!(write, &read); 1314 1315 // another mmap should contain the write 1316 let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; 1317 (&mmap2[..]).read_exact(&mut read).unwrap(); 1318 assert_eq!(write, &read); 1319 1320 let mmap = mmap.make_exec().expect("make_exec"); 1321 1322 drop(mmap); 1323 } 1324 1325 #[test] mprotect_copy()1326 fn mprotect_copy() { 1327 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 1328 let path = tempdir.path().join("mmap"); 1329 1330 let mut options = OpenOptions::new(); 1331 #[cfg(windows)] 1332 options.access_mode(GENERIC_ALL); 1333 1334 let mut file = options 1335 .read(true) 1336 .write(true) 1337 .create(true) 1338 .open(&path) 1339 .expect("open"); 1340 file.set_len(256_u64).expect("set_len"); 1341 1342 let mmap = unsafe { MmapOptions::new().map_copy(&file).expect("map_mut") }; 1343 1344 let mmap = mmap.make_read_only().expect("make_read_only"); 1345 let mut mmap = mmap.make_mut().expect("make_mut"); 1346 1347 let nulls = b"\0\0\0\0\0\0"; 1348 let write = b"abc123"; 1349 let mut read = [0u8; 6]; 1350 1351 (&mut mmap[..]).write_all(write).unwrap(); 1352 mmap.flush().unwrap(); 1353 1354 // The mmap contains the write 1355 (&mmap[..]).read_exact(&mut read).unwrap(); 1356 assert_eq!(write, &read); 1357 1358 // The file does not contain the write 1359 file.read_exact(&mut read).unwrap(); 1360 assert_eq!(nulls, &read); 1361 1362 // another mmap does not contain the write 1363 let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; 1364 (&mmap2[..]).read_exact(&mut read).unwrap(); 1365 assert_eq!(nulls, &read); 1366 1367 let mmap = mmap.make_exec().expect("make_exec"); 1368 1369 drop(mmap); 1370 } 1371 1372 #[test] mprotect_anon()1373 fn mprotect_anon() { 1374 let mmap = MmapMut::map_anon(256).expect("map_mut"); 1375 1376 let mmap = mmap.make_read_only().expect("make_read_only"); 1377 let mmap = mmap.make_mut().expect("make_mut"); 1378 let mmap = mmap.make_exec().expect("make_exec"); 1379 drop(mmap); 1380 } 1381 1382 #[test] raw()1383 fn raw() { 1384 let tempdir = tempdir::TempDir::new("mmap").unwrap(); 1385 let path = tempdir.path().join("mmapraw"); 1386 1387 let mut options = OpenOptions::new(); 1388 let mut file = options 1389 .read(true) 1390 .write(true) 1391 .create(true) 1392 .open(&path) 1393 .expect("open"); 1394 file.write_all(b"abc123").unwrap(); 1395 let mmap = MmapOptions::new().map_raw(&file).unwrap(); 1396 assert_eq!(mmap.len(), 6); 1397 assert!(!mmap.as_ptr().is_null()); 1398 assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a'); 1399 } 1400 1401 /// Something that relies on StableDeref 1402 #[test] 1403 #[cfg(feature = "stable_deref_trait")] owning_ref()1404 fn owning_ref() { 1405 extern crate owning_ref; 1406 1407 let mut map = MmapMut::map_anon(128).unwrap(); 1408 map[10] = 42; 1409 let owning = owning_ref::OwningRef::new(map); 1410 let sliced = owning.map(|map| &map[10..20]); 1411 assert_eq!(42, sliced[0]); 1412 1413 let map = sliced.into_owner().make_read_only().unwrap(); 1414 let owning = owning_ref::OwningRef::new(map); 1415 let sliced = owning.map(|map| &map[10..20]); 1416 assert_eq!(42, sliced[0]); 1417 } 1418 } 1419