stak_libc/
mmap.rs

1use core::{ffi::CStr, ops::Deref, ptr::null_mut, slice};
2use rustix::{
3    fs::{self, Mode, OFlags},
4    io,
5    mm::{MapFlags, ProtFlags, mmap, munmap},
6};
7
8/// A mmap.
9pub struct Mmap {
10    ptr: *mut u8,
11    len: usize,
12}
13
14impl Mmap {
15    /// Creates a mmap opening a file at a path.
16    pub fn new(path: &CStr) -> io::Result<Self> {
17        let len = fs::stat(path)?.st_size as _;
18        // spell-checker: disable-next-line
19        let descriptor = fs::open(path, OFlags::RDONLY, Mode::RUSR)?;
20
21        Ok(Self {
22            // SAFETY: The passed pointer is null.
23            ptr: unsafe {
24                mmap(
25                    null_mut(),
26                    len,
27                    ProtFlags::READ,
28                    MapFlags::PRIVATE,
29                    descriptor,
30                    0,
31                )?
32            } as _,
33            len,
34        })
35    }
36}
37
38impl Deref for Mmap {
39    type Target = [u8];
40
41    fn deref(&self) -> &Self::Target {
42        // SAFETY: `self.ptr` is guaranteed to have the length of `self.len`.
43        unsafe { slice::from_raw_parts(self.ptr, self.len) }
44    }
45}
46
47impl Drop for Mmap {
48    fn drop(&mut self) {
49        // SAFETY: We ensure that the `mmap` call succeeds.
50        unsafe { munmap(self.ptr as _, self.len).unwrap() }
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn read_file() {
60        Mmap::new(c"src/lib.rs").unwrap();
61    }
62}