use memmap2::MmapOptions;
use std::path::Path;
use super::raw::open_file_safe;
pub(in crate::filesystem) enum FileBytes {
Mmap(memmap2::Mmap),
Owned(Vec<u8>),
}
impl FileBytes {
pub fn as_slice(&self) -> &[u8] {
match self {
FileBytes::Mmap(m) => m,
FileBytes::Owned(v) => v,
}
}
#[cfg(test)]
pub fn len(&self) -> usize {
self.as_slice().len()
}
}
pub(in crate::filesystem) fn read_file_for_compressed_input(
path: &Path,
size_cap: u64,
) -> Option<FileBytes> {
let file = open_file_safe(path).ok()?;
let metadata = file.metadata().ok()?;
if metadata.len() > size_cap {
tracing::warn!(
path = %path.display(),
size = metadata.len(),
cap = size_cap,
"compressed file exceeds size cap; refusing to map"
);
return None;
}
if metadata.len() == 0 {
return Some(FileBytes::Owned(Vec::new()));
}
#[cfg(unix)]
{
use std::os::unix::io::AsRawFd;
if unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) } != 0 {
return std::fs::read(path).ok().map(FileBytes::Owned);
}
}
match unsafe { MmapOptions::new().map(&file) } {
Ok(mmap) => {
#[cfg(unix)]
{
unsafe {
libc::madvise(
mmap.as_ptr() as *mut libc::c_void,
mmap.len(),
libc::MADV_SEQUENTIAL,
);
}
use std::os::unix::io::AsRawFd;
unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_UN) };
}
Some(FileBytes::Mmap(mmap))
}
Err(_) => {
#[cfg(unix)]
{
use std::os::unix::io::AsRawFd;
unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_UN) };
}
std::fs::read(path).ok().map(FileBytes::Owned)
}
}
}