c-scape 0.22.3

A libc bottom-half implementation in Rust
Documentation
use rustix::fd::BorrowedFd;
use rustix::mm::{MapFlags, MlockAllFlags, MprotectFlags, MremapFlags, ProtFlags};

use core::ffi::c_void;
use errno::{set_errno, Errno};
use libc::{c_int, c_uint, off64_t, off_t, size_t};

use crate::convert_res;

#[no_mangle]
unsafe extern "C" fn mmap(
    addr: *mut c_void,
    length: size_t,
    prot: c_int,
    flags: c_int,
    fd: c_int,
    offset: off_t,
) -> *mut c_void {
    libc!(libc::mmap(addr, length, prot, flags, fd, offset));

    mmap64(addr, length, prot, flags, fd, offset as off64_t)
}

#[no_mangle]
unsafe extern "C" fn mmap64(
    addr: *mut c_void,
    length: size_t,
    prot: c_int,
    flags: c_int,
    fd: c_int,
    offset: off64_t,
) -> *mut c_void {
    libc!(libc::mmap64(addr, length, prot, flags, fd, offset));

    let anon = flags & libc::MAP_ANONYMOUS == libc::MAP_ANONYMOUS;
    let prot = ProtFlags::from_bits(prot as _).unwrap();
    let flags = MapFlags::from_bits((flags & !libc::MAP_ANONYMOUS) as _).unwrap();

    match convert_res(if anon {
        rustix::mm::mmap_anonymous(addr, length, prot, flags)
    } else {
        if fd == -1 {
            set_errno(Errno(libc::EBADF));
            return libc::MAP_FAILED;
        }

        rustix::mm::mmap(
            addr,
            length,
            prot,
            flags,
            BorrowedFd::borrow_raw(fd),
            offset as _,
        )
    }) {
        Some(ptr) => ptr,
        None => libc::MAP_FAILED,
    }
}

#[no_mangle]
unsafe extern "C" fn munmap(ptr: *mut c_void, len: size_t) -> c_int {
    libc!(libc::munmap(ptr, len));

    match convert_res(rustix::mm::munmap(ptr, len)) {
        Some(()) => 0,
        None => -1,
    }
}

#[no_mangle]
unsafe extern "C" fn mremap(
    old_address: *mut c_void,
    old_size: size_t,
    new_size: size_t,
    flags: c_int,
    mut args: ...
) -> *mut c_void {
    if (flags & libc::MREMAP_FIXED) == libc::MREMAP_FIXED {
        let new_address = args.arg::<*mut c_void>();
        libc!(libc::mremap(
            old_address,
            old_size,
            new_size,
            flags,
            new_address
        ));

        let flags = flags & !libc::MREMAP_FIXED;
        let flags = MremapFlags::from_bits(flags as _).unwrap();
        match convert_res(rustix::mm::mremap_fixed(
            old_address,
            old_size,
            new_size,
            flags,
            new_address,
        )) {
            Some(new_address) => new_address,
            None => libc::MAP_FAILED,
        }
    } else {
        libc!(libc::mremap(old_address, old_size, new_size, flags));

        let flags = MremapFlags::from_bits(flags as _).unwrap();
        match convert_res(rustix::mm::mremap(old_address, old_size, new_size, flags)) {
            Some(new_address) => new_address,
            None => libc::MAP_FAILED,
        }
    }
}

#[no_mangle]
unsafe extern "C" fn mprotect(addr: *mut c_void, length: size_t, prot: c_int) -> c_int {
    libc!(libc::mprotect(addr, length, prot));

    let prot = MprotectFlags::from_bits(prot as _).unwrap();
    match convert_res(rustix::mm::mprotect(addr, length, prot)) {
        Some(()) => 0,
        None => -1,
    }
}

#[no_mangle]
unsafe extern "C" fn madvise(addr: *mut c_void, length: size_t, advice: c_int) -> c_int {
    libc!(libc::madvise(addr, length, advice));

    use rustix::mm::Advice;

    let advice = match advice {
        libc::MADV_NORMAL => Advice::Normal,
        libc::MADV_SEQUENTIAL => Advice::Sequential,
        libc::MADV_RANDOM => Advice::Random,
        libc::MADV_WILLNEED => Advice::WillNeed,
        libc::MADV_DONTNEED => Advice::LinuxDontNeed,
        libc::MADV_FREE => Advice::LinuxFree,
        libc::MADV_REMOVE => Advice::LinuxRemove,
        libc::MADV_DONTFORK => Advice::LinuxDontFork,
        libc::MADV_DOFORK => Advice::LinuxDoFork,
        libc::MADV_HWPOISON => Advice::LinuxHwPoison,
        #[cfg(not(any(
            target_arch = "mips",
            target_arch = "mips32r6",
            target_arch = "mips64",
            target_arch = "mips64r6"
        )))]
        libc::MADV_SOFT_OFFLINE => Advice::LinuxSoftOffline,
        libc::MADV_MERGEABLE => Advice::LinuxMergeable,
        libc::MADV_UNMERGEABLE => Advice::LinuxUnmergeable,
        libc::MADV_HUGEPAGE => Advice::LinuxHugepage,
        libc::MADV_NOHUGEPAGE => Advice::LinuxNoHugepage,
        libc::MADV_DONTDUMP => Advice::LinuxDontDump,
        libc::MADV_DODUMP => Advice::LinuxDoDump,
        libc::MADV_WIPEONFORK => Advice::LinuxWipeOnFork,
        libc::MADV_KEEPONFORK => Advice::LinuxKeepOnFork,
        libc::MADV_COLD => Advice::LinuxCold,
        libc::MADV_PAGEOUT => Advice::LinuxPageOut,
        libc::MADV_POPULATE_READ => Advice::LinuxPopulateRead,
        libc::MADV_POPULATE_WRITE => Advice::LinuxPopulateWrite,
        libc::MADV_DONTNEED_LOCKED => Advice::LinuxDontneedLocked,
        _ => {
            set_errno(Errno(libc::EINVAL));
            return -1;
        }
    };
    match convert_res(rustix::mm::madvise(addr, length, advice)) {
        Some(()) => 0,
        None => -1,
    }
}

#[no_mangle]
unsafe extern "C" fn mlock(addr: *mut c_void, len: size_t) -> c_int {
    libc!(libc::mlock(addr, len));

    match convert_res(rustix::mm::mlock(addr.cast(), len)) {
        Some(()) => 0,
        None => -1,
    }
}

#[no_mangle]
unsafe extern "C" fn mlock2(addr: *const c_void, len: size_t, flags: c_uint) -> c_int {
    libc!(libc::mlock2(addr, len, flags));

    let flags = rustix::mm::MlockFlags::from_bits_retain(flags);
    match convert_res(rustix::mm::mlock_with(addr.cast_mut(), len, flags)) {
        Some(()) => 0,
        None => -1,
    }
}

#[no_mangle]
unsafe extern "C" fn munlock(addr: *const c_void, len: size_t) -> c_int {
    libc!(libc::munlock(addr, len));

    match convert_res(rustix::mm::munlock(addr.cast_mut(), len)) {
        Some(()) => 0,
        None => -1,
    }
}

#[no_mangle]
unsafe extern "C" fn mlockall(flags: c_int) -> c_int {
    libc!(libc::mlockall(flags));

    let flags = MlockAllFlags::from_bits(flags as _).unwrap();
    match convert_res(rustix::mm::mlockall(flags)) {
        Some(()) => 0,
        None => -1,
    }
}

#[no_mangle]
unsafe extern "C" fn munlockall() -> c_int {
    libc!(libc::munlockall());

    match convert_res(rustix::mm::munlockall()) {
        Some(()) => 0,
        None => -1,
    }
}

#[no_mangle]
unsafe extern "C" fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int {
    libc!(libc::msync(addr, len, flags));

    let flags = rustix::mm::MsyncFlags::from_bits_retain(flags as _);
    match convert_res(rustix::mm::msync(addr, len, flags)) {
        Some(()) => 0,
        None => -1,
    }
}