mod allocate;
pub(crate) mod call;
mod copy_range;
pub(crate) mod file;
mod file_ops;
mod lock;
#[cfg(target_os = "linux")]
mod open_cached;
mod ops;
mod read_dir;
#[cfg(ring)]
pub(crate) mod ring;
mod sync_dir;
pub use self::allocate::Allocate;
pub use std::fs::{FileTimes, FileType, Metadata, Permissions, TryLockError};
#[cfg(unix)]
pub use self::ops::symlink;
pub use self::ops::{
DirBuilder, OpenOptions, canonicalize, copy, create_dir, create_dir_all, hard_link, metadata,
read, read_link, read_to_string, remove_dir, remove_dir_all, remove_file, rename,
set_permissions, symlink_metadata, try_exists, write,
};
#[cfg(windows)]
pub use self::ops::{symlink_dir, symlink_file};
pub use self::read_dir::{DirEntry, ReadDir, read_dir};
pub use self::sync_dir::sync_dir;
pub type File = Handle<std::fs::File>;
use core::pin::Pin;
use core::task::{Context, Poll};
use std::fs::File as StdFile;
use std::io::{self, SeekFrom};
use std::path::Path;
use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite};
use crate::buf::owned::{IoBuf, IoBufMut, OwnedBuf};
use crate::buf::vectored::{self, IoVecBuf, IoVecBufMut};
use crate::io::Handle;
use crate::io::source::Kind;
impl Handle<StdFile> {
pub async fn open(p: impl AsRef<Path>) -> io::Result<Handle<StdFile>> {
#[cfg(target_os = "linux")]
if let Some(file) = open_cached::open(p.as_ref()) {
return Handle::adopt(file, Kind::File);
}
let path = p.as_ref().to_path_buf();
let file = ops::blocking(move || StdFile::open(path)).await?;
Handle::new(file)
}
fn is_regular(&self) -> bool {
self.source.kind() == Kind::File
}
pub async fn read_owned<B>(&self, buf: B) -> (io::Result<usize>, B)
where
B: IoBufMut,
{
if !self.is_regular() {
return self.source().read_owned(buf).await;
}
match self.file() {
Ok(file) => file.read_owned(buf).await,
Err(err) => (Err(err), buf),
}
}
pub async fn write_owned<B>(&self, buf: B) -> (io::Result<usize>, B)
where
B: IoBuf,
{
if !self.is_regular() {
return self.source().write_owned(buf).await;
}
match self.file() {
Ok(file) => file.write_owned(buf).await,
Err(err) => (Err(err), buf),
}
}
pub async fn read_vectored_owned<V>(&self, bufs: V) -> (io::Result<usize>, V)
where
V: IoVecBufMut,
{
let bufs = OwnedBuf::vectored_read(vectored::filled(bufs));
let (result, bufs) = self.read_owned(bufs).await;
(result, vectored::into_filled(bufs.into_segments()))
}
pub async fn write_vectored_owned<V>(&self, bufs: V) -> (io::Result<usize>, V)
where
V: IoVecBuf,
{
let bufs = OwnedBuf::vectored(vectored::written(bufs));
let (result, bufs) = self.write_owned(bufs).await;
(result, vectored::into_written(bufs.into_segments()))
}
}
macro_rules! file_io {
($($ty:ty),*) => {$(
impl AsyncRead for $ty {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
if !self.is_regular() {
return self.source().poll_read(cx, buf, false);
}
match self.file() {
Ok(file) => file.poll_read(cx, buf),
Err(err) => Poll::Ready(Err(err)),
}
}
fn poll_read_vectored(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &mut [io::IoSliceMut<'_>],
) -> Poll<io::Result<usize>> {
if !self.is_regular() {
return self.source().poll_read_vectored(cx, bufs);
}
match self.file() {
Ok(file) => file.poll_read_vectored(cx, bufs),
Err(err) => Poll::Ready(Err(err)),
}
}
}
impl AsyncWrite for $ty {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
if !self.is_regular() {
return self.source().poll_write(cx, buf);
}
match self.file() {
Ok(file) => file.poll_write(cx, buf),
Err(err) => Poll::Ready(Err(err)),
}
}
fn poll_write_vectored(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
bufs: &[io::IoSlice<'_>],
) -> Poll<io::Result<usize>> {
if !self.is_regular() {
return self.source().poll_write_vectored(cx, bufs);
}
match self.file() {
Ok(file) => file.poll_write_vectored(cx, bufs),
Err(err) => Poll::Ready(Err(err)),
}
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
if !self.is_regular() {
return self.source().poll_flush(cx);
}
match self.file() {
Ok(file) => file.poll_flush(cx),
Err(err) => Poll::Ready(Err(err)),
}
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.poll_flush(cx)
}
}
)*};
}
file_io!(Handle<StdFile>, &Handle<StdFile>);
impl AsyncSeek for Handle<StdFile> {
fn poll_seek(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
pos: SeekFrom,
) -> Poll<io::Result<u64>> {
if !self.is_regular() {
return Poll::Ready(Err(io::Error::new(
io::ErrorKind::Unsupported,
"the file is a stream, which has no position to seek",
)));
}
match self.file() {
Ok(file) => file.poll_seek(cx, pos),
Err(err) => Poll::Ready(Err(err)),
}
}
}
impl AsyncBufRead for Handle<StdFile> {
fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
let this = Pin::into_inner(self);
if !this.is_regular() {
return Poll::Ready(Err(io::Error::new(
io::ErrorKind::Unsupported,
"buffered reads are for regular files; wrap a stream in a buffered reader",
)));
}
let file = match this.file() {
Ok(file) => file,
Err(err) => return Poll::Ready(Err(err)),
};
file.poll_fill_buf(cx).map_ok(|(ptr, len)| {
unsafe { core::slice::from_raw_parts(ptr, len) }
})
}
fn consume(self: Pin<&mut Self>, amt: usize) {
if let Some(file) = self.file.get() {
file.consume(amt);
}
}
}
#[cfg(test)]
mod tests;