1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
extern crate libc;
use std::{io, mem, ptr, slice};
use std::fs::File;
use std::path::Path;
use std::os::unix::io::AsRawFd;
pub struct FileMap {
ptr: *mut libc::c_void,
size: usize,
}
impl FileMap {
pub fn open<P: AsRef<Path> + ?Sized>(path: &P) -> io::Result<FileMap> {
Self::_open(path.as_ref())
}
fn _open(path: &Path) -> io::Result<FileMap> {
let file = File::open(path)?;
let fd = file.as_raw_fd();
let size = unsafe {
let mut stat = mem::uninitialized();
if libc::fstat(fd, &mut stat) < 0 {
return Err(io::Error::last_os_error());
}
let page_size = libc::sysconf(libc::_SC_PAGE_SIZE) as usize;
(stat.st_size as usize + page_size - 1) & !(page_size - 1)
};
unsafe {
let ptr = libc::mmap(
ptr::null_mut(),
size as libc::size_t,
libc::PROT_READ,
libc::MAP_PRIVATE,
fd,
0
);
if ptr == libc::MAP_FAILED {
Err(io::Error::last_os_error())
}
else {
Ok(FileMap { ptr, size })
}
}
}
}
impl Drop for FileMap {
fn drop(&mut self) {
unsafe {
let _result = libc::munmap(self.ptr, self.size as libc::size_t);
debug_assert_eq!(_result, 0, "unable to munmap: {}", io::Error::last_os_error());
}
}
}
impl AsRef<[u8]> for FileMap {
fn as_ref(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(self.ptr as *const _, self.size)
}
}
}