use std::fs::File;
use std::io;
use std::os::unix::fs::FileExt;
use std::os::unix::io::AsRawFd;
pub(crate) trait Backing: Send {
#[cfg_attr(not(test), allow(dead_code))]
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
#[cfg_attr(not(test), allow(dead_code))]
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
fn sync_data(&self) -> io::Result<()>;
unsafe fn preadv(&self, iovs: &[libc::iovec], offset: u64) -> io::Result<usize>;
unsafe fn pwritev(&self, iovs: &[libc::iovec], offset: u64) -> io::Result<usize>;
}
impl Backing for File {
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
FileExt::read_at(self, buf, offset)
}
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
FileExt::write_at(self, buf, offset)
}
fn sync_data(&self) -> io::Result<()> {
File::sync_data(self)
}
unsafe fn preadv(&self, iovs: &[libc::iovec], offset: u64) -> io::Result<usize> {
let r = unsafe {
libc::preadv(
self.as_raw_fd(),
iovs.as_ptr(),
iovs.len() as libc::c_int,
offset as libc::off_t,
)
};
if r < 0 {
Err(io::Error::last_os_error())
} else {
Ok(r as usize)
}
}
unsafe fn pwritev(&self, iovs: &[libc::iovec], offset: u64) -> io::Result<usize> {
let r = unsafe {
libc::pwritev(
self.as_raw_fd(),
iovs.as_ptr(),
iovs.len() as libc::c_int,
offset as libc::off_t,
)
};
if r < 0 {
Err(io::Error::last_os_error())
} else {
Ok(r as usize)
}
}
}
pub(crate) fn advance_iovecs(iovs: &mut [libc::iovec], mut n: usize) -> &mut [libc::iovec] {
let mut i = 0;
while i < iovs.len() && n >= iovs[i].iov_len {
n -= iovs[i].iov_len;
i += 1;
}
let rest = &mut iovs[i..];
if n > 0 {
rest[0].iov_base = (rest[0].iov_base as *mut u8).wrapping_add(n) as *mut libc::c_void;
rest[0].iov_len -= n;
}
rest
}