use std::{
ffi::OsString,
fs::{Metadata, Permissions},
io,
path::{Path, PathBuf},
};
use crate::blocking::spawn_blocking;
fn join_err(e: crate::executor::JoinError) -> io::Error {
io::Error::other(format!("filesystem operation failed: {e}"))
}
pub async fn read(path: impl AsRef<Path>) -> io::Result<Vec<u8>> {
let path = path.as_ref().to_path_buf();
spawn_blocking(move || std::fs::read(path))
.await
.map_err(join_err)?
}
pub async fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> io::Result<()> {
let path = path.as_ref().to_path_buf();
let data = contents.as_ref().to_vec();
spawn_blocking(move || std::fs::write(path, data))
.await
.map_err(join_err)?
}
pub async fn metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
let path = path.as_ref().to_path_buf();
spawn_blocking(move || std::fs::metadata(path))
.await
.map_err(join_err)?
}
pub async fn symlink_metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
let path = path.as_ref().to_path_buf();
spawn_blocking(move || std::fs::symlink_metadata(path))
.await
.map_err(join_err)?
}
pub async fn remove_file(path: impl AsRef<Path>) -> io::Result<()> {
let path = path.as_ref().to_path_buf();
spawn_blocking(move || std::fs::remove_file(path))
.await
.map_err(join_err)?
}
pub async fn remove_dir(path: impl AsRef<Path>) -> io::Result<()> {
let path = path.as_ref().to_path_buf();
spawn_blocking(move || std::fs::remove_dir(path))
.await
.map_err(join_err)?
}
pub async fn remove_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
let path = path.as_ref().to_path_buf();
spawn_blocking(move || std::fs::remove_dir_all(path))
.await
.map_err(join_err)?
}
pub async fn rename(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
let from = from.as_ref().to_path_buf();
let to = to.as_ref().to_path_buf();
spawn_blocking(move || std::fs::rename(from, to))
.await
.map_err(join_err)?
}
pub async fn create_dir(path: impl AsRef<Path>) -> io::Result<()> {
let path = path.as_ref().to_path_buf();
spawn_blocking(move || std::fs::create_dir(path))
.await
.map_err(join_err)?
}
pub async fn create_dir_all(path: impl AsRef<Path>) -> io::Result<()> {
let path = path.as_ref().to_path_buf();
spawn_blocking(move || std::fs::create_dir_all(path))
.await
.map_err(join_err)?
}
pub async fn copy(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<u64> {
let from = from.as_ref().to_path_buf();
let to = to.as_ref().to_path_buf();
spawn_blocking(move || std::fs::copy(from, to))
.await
.map_err(join_err)?
}
pub async fn set_permissions(path: impl AsRef<Path>, perm: Permissions) -> io::Result<()> {
let path = path.as_ref().to_path_buf();
spawn_blocking(move || std::fs::set_permissions(path, perm))
.await
.map_err(join_err)?
}
#[derive(Debug, Clone)]
pub struct DirEntry {
path: PathBuf,
file_name: OsString,
file_type: std::fs::FileType,
}
impl DirEntry {
pub fn path(&self) -> PathBuf {
self.path.clone()
}
pub fn file_name(&self) -> OsString {
self.file_name.clone()
}
pub fn file_type(&self) -> std::fs::FileType {
self.file_type
}
pub async fn metadata(&self) -> io::Result<Metadata> {
let p = self.path.clone();
spawn_blocking(move || std::fs::symlink_metadata(p))
.await
.map_err(join_err)?
}
}
pub struct ReadDir {
entries: std::vec::IntoIter<io::Result<DirEntry>>,
}
impl ReadDir {
pub async fn next_entry(&mut self) -> io::Result<Option<DirEntry>> {
match self.entries.next() {
Some(Ok(entry)) => Ok(Some(entry)),
Some(Err(e)) => Err(e),
None => Ok(None),
}
}
}
pub async fn read_dir(path: impl AsRef<Path>) -> io::Result<ReadDir> {
let path = path.as_ref().to_path_buf();
let entries = spawn_blocking(move || -> io::Result<Vec<io::Result<DirEntry>>> {
let rd = std::fs::read_dir(path)?;
let mut out = Vec::new();
for res in rd {
out.push(res.and_then(|e| {
let ft = e.file_type()?;
Ok(DirEntry {
path: e.path(),
file_name: e.file_name(),
file_type: ft,
})
}));
}
Ok(out)
})
.await
.map_err(join_err)??;
Ok(ReadDir {
entries: entries.into_iter(),
})
}