use crate::buf::fixed::FixedBuf;
use crate::buf::{BoundedBuf, BoundedBufMut, IoBuf, IoBufMut, Slice};
use crate::fs::OpenOptions;
use crate::io::SharedFd;
use crate::runtime::driver::op::Op;
use crate::{UnsubmittedOneshot, UnsubmittedWrite};
use std::fmt;
use std::io;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::path::Path;
pub struct File {
pub(crate) fd: SharedFd,
}
impl File {
pub async fn open(path: impl AsRef<Path>) -> io::Result<File> {
OpenOptions::new().read(true).open(path).await
}
pub async fn create(path: impl AsRef<Path>) -> io::Result<File> {
OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path)
.await
}
pub(crate) fn from_shared_fd(fd: SharedFd) -> File {
File { fd }
}
pub fn from_std(file: std::fs::File) -> File {
File::from_shared_fd(SharedFd::new(file.into_raw_fd()))
}
pub async fn read_at<T: BoundedBufMut>(&self, buf: T, pos: u64) -> crate::BufResult<usize, T> {
let op = Op::read_at(&self.fd, buf, pos).unwrap();
op.await
}
pub async fn readv_at<T: BoundedBufMut>(&self, bufs: Vec<T>, pos: u64) -> crate::BufResult<usize, Vec<T>> {
let op = Op::readv_at(&self.fd, bufs, pos).unwrap();
op.await
}
pub async fn writev_at<T: BoundedBuf>(&self, buf: Vec<T>, pos: u64) -> crate::BufResult<usize, Vec<T>> {
let op = Op::writev_at(&self.fd, buf, pos).unwrap();
op.await
}
pub async fn writev_at_all<T: BoundedBuf>(
&self,
buf: Vec<T>,
pos: Option<u64>, ) -> crate::BufResult<usize, Vec<T>> {
let op = crate::io::writev_at_all(&self.fd, buf, pos);
op.await
}
pub async fn read_exact_at<T>(&self, buf: T, pos: u64) -> crate::BufResult<(), T>
where
T: BoundedBufMut,
{
let orig_bounds = buf.bounds();
let (res, buf) = self.read_exact_slice_at(buf.slice_full(), pos).await;
(res, T::from_buf_bounds(buf, orig_bounds))
}
async fn read_exact_slice_at<T: IoBufMut>(&self, mut buf: Slice<T>, mut pos: u64) -> crate::BufResult<(), T> {
if pos.checked_add(buf.bytes_total() as u64).is_none() {
return (
Err(io::Error::new(io::ErrorKind::InvalidInput, "buffer too large for file")),
buf.into_inner(),
);
}
while buf.bytes_total() != 0 {
let (res, slice) = self.read_at(buf, pos).await;
match res {
Ok(0) => {
return (
Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"failed to fill whole buffer",
)),
slice.into_inner(),
);
}
Ok(n) => {
pos += n as u64;
buf = slice.slice(n..);
}
Err(e) => return (Err(e), slice.into_inner()),
};
}
(Ok(()), buf.into_inner())
}
pub async fn read_fixed_at<T>(&self, buf: T, pos: u64) -> crate::BufResult<usize, T>
where
T: BoundedBufMut<BufMut = FixedBuf>,
{
let op = Op::read_fixed_at(&self.fd, buf, pos).unwrap();
op.await
}
pub fn write_at<T: BoundedBuf>(&self, buf: T, pos: u64) -> UnsubmittedWrite<T> {
UnsubmittedOneshot::write_at(&self.fd, buf, pos)
}
pub async fn write_all_at<T>(&self, buf: T, pos: u64) -> crate::BufResult<(), T>
where
T: BoundedBuf,
{
let orig_bounds = buf.bounds();
let (res, buf) = self.write_all_slice_at(buf.slice_full(), pos).await;
(res, T::from_buf_bounds(buf, orig_bounds))
}
async fn write_all_slice_at<T: IoBuf>(&self, mut buf: Slice<T>, mut pos: u64) -> crate::BufResult<(), T> {
if pos.checked_add(buf.bytes_init() as u64).is_none() {
return (
Err(io::Error::new(io::ErrorKind::InvalidInput, "buffer too large for file")),
buf.into_inner(),
);
}
while buf.bytes_init() != 0 {
let (res, slice) = self.write_at(buf, pos).submit().await;
match res {
Ok(0) => {
return (
Err(io::Error::new(io::ErrorKind::WriteZero, "failed to write whole buffer")),
slice.into_inner(),
);
}
Ok(n) => {
pos += n as u64;
buf = slice.slice(n..);
}
Err(e) => return (Err(e), slice.into_inner()),
};
}
(Ok(()), buf.into_inner())
}
pub async fn write_fixed_at<T>(&self, buf: T, pos: u64) -> crate::BufResult<usize, T>
where
T: BoundedBuf<Buf = FixedBuf>,
{
let op = Op::write_fixed_at(&self.fd, buf, pos).unwrap();
op.await
}
pub async fn write_fixed_all_at<T>(&self, buf: T, pos: u64) -> crate::BufResult<(), T>
where
T: BoundedBuf<Buf = FixedBuf>,
{
let orig_bounds = buf.bounds();
let (res, buf) = self.write_fixed_all_at_slice(buf.slice_full(), pos).await;
(res, T::from_buf_bounds(buf, orig_bounds))
}
async fn write_fixed_all_at_slice(&self, mut buf: Slice<FixedBuf>, mut pos: u64) -> crate::BufResult<(), FixedBuf> {
if pos.checked_add(buf.bytes_init() as u64).is_none() {
return (
Err(io::Error::new(io::ErrorKind::InvalidInput, "buffer too large for file")),
buf.into_inner(),
);
}
while buf.bytes_init() != 0 {
let (res, slice) = self.write_fixed_at(buf, pos).await;
match res {
Ok(0) => {
return (
Err(io::Error::new(io::ErrorKind::WriteZero, "failed to write whole buffer")),
slice.into_inner(),
);
}
Ok(n) => {
pos += n as u64;
buf = slice.slice(n..);
}
Err(e) => return (Err(e), slice.into_inner()),
};
}
(Ok(()), buf.into_inner())
}
pub async fn sync_all(&self) -> io::Result<()> {
Op::fsync(&self.fd)?.await
}
pub async fn sync_data(&self) -> io::Result<()> {
Op::datasync(&self.fd)?.await
}
pub async fn fallocate(&self, offset: u64, len: u64, flags: i32) -> io::Result<()> {
Op::fallocate(&self.fd, offset, len, flags)?.await
}
pub async fn close(mut self) -> io::Result<()> {
self.fd.close().await
}
}
impl FromRawFd for File {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
File::from_shared_fd(SharedFd::new(fd))
}
}
impl AsRawFd for File {
fn as_raw_fd(&self) -> RawFd {
self.fd.raw_fd()
}
}
impl fmt::Debug for File {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("File").field("fd", &self.fd.raw_fd()).finish()
}
}
pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
Op::unlink_file(path.as_ref())?.await
}
pub async fn rename(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
Op::rename_at(from.as_ref(), to.as_ref(), 0)?.await
}