use std::io;
use std::path::Path;
type LocalBoxFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + 'a>>;
pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
DirBuilder::new().recursive(true).create(path.as_ref()).await
}
#[derive(Debug)]
pub struct DirBuilder {
inner: fs_imp::DirBuilder,
recursive: bool,
}
impl Default for DirBuilder {
fn default() -> Self {
Self::new()
}
}
impl DirBuilder {
#[must_use]
pub fn new() -> DirBuilder {
DirBuilder {
inner: fs_imp::DirBuilder::new(),
recursive: false,
}
}
#[must_use]
pub fn recursive(&mut self, recursive: bool) -> &mut Self {
self.recursive = recursive;
self
}
#[must_use]
pub fn mode(&mut self, mode: u32) -> &mut Self {
self.inner.set_mode(mode);
self
}
pub async fn create<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
self._create(path.as_ref()).await
}
async fn _create(&self, path: &Path) -> io::Result<()> {
if self.recursive {
self.recurse_create_dir_all(path).await
} else {
self.inner.mkdir(path).await
}
}
fn recurse_create_dir_all<'a>(&'a self, path: &'a Path) -> LocalBoxFuture<'a, io::Result<()>> {
Box::pin(async move {
if path == Path::new("") {
return Ok(());
}
match self.inner.mkdir(path).await {
Ok(()) => return Ok(()),
Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
Err(_) if is_dir(path).await => return Ok(()),
Err(e) => return Err(e),
}
match path.parent() {
Some(p) => self.recurse_create_dir_all(p).await?,
None => {
return Err(std::io::Error::other("failed to create whole tree"));
}
}
match self.inner.mkdir(path).await {
Ok(()) => Ok(()),
Err(_) if is_dir(path).await => Ok(()),
Err(e) => Err(e),
}
})
}
}
mod fs_imp {
use crate::runtime::driver::op::Op;
use libc::mode_t;
use std::path::Path;
#[derive(Debug)]
pub struct DirBuilder {
mode: mode_t,
}
impl DirBuilder {
pub fn new() -> DirBuilder {
DirBuilder { mode: 0o777 }
}
pub async fn mkdir(&self, p: &Path) -> std::io::Result<()> {
Op::make_dir(p, self.mode)?.await
}
pub fn set_mode(&mut self, mode: u32) {
self.mode = mode as mode_t;
}
}
}
async fn is_dir<P: AsRef<Path>>(path: P) -> bool {
let mut builder = crate::fs::StatxBuilder::new();
if builder.mask(libc::STATX_TYPE).pathname(path).is_err() {
return false;
}
let res = builder.statx().await;
match res {
Ok(statx) => (u32::from(statx.stx_mode) & libc::S_IFMT) == libc::S_IFDIR,
Err(_) => false,
}
}