use crate::{
io::{dma_file::DmaFile, glommio_file::GlommioFile},
sys,
GlommioError,
};
use std::{
cell::Ref,
io,
os::unix::io::{AsRawFd, FromRawFd, RawFd},
path::Path,
};
type Result<T> = crate::Result<T, ()>;
#[derive(Debug)]
pub struct Directory {
file: GlommioFile,
}
impl AsRawFd for Directory {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
impl Directory {
pub fn try_clone(&self) -> Result<Directory> {
let fd = sys::duplicate_file(self.file.as_raw_fd()).map_err(|source| {
GlommioError::create_enhanced(
source,
"Cloning directory",
self.file.path.borrow().as_ref(),
Some(self.file.as_raw_fd()),
)
})?;
let file =
unsafe { GlommioFile::from_raw_fd(fd as _) }.with_path(self.file.path.borrow().clone());
Ok(Directory { file })
}
pub async fn open<P: AsRef<Path>>(path: P) -> Result<Directory> {
let path = path.as_ref().to_owned();
let flags = libc::O_DIRECTORY | libc::O_CLOEXEC;
let reactor = crate::executor().reactor();
let source = reactor.open_at(-1, &path, flags, 0o755);
let fd = source.collect_rw().await.map_err(|source| {
GlommioError::create_enhanced(source, "Opening directory", Some(&path), None)
})?;
let file = unsafe { GlommioFile::from_raw_fd(fd as _) }.with_path(Some(path));
Ok(Directory { file })
}
pub async fn open_file<P: AsRef<Path>>(&self, path: P) -> Result<DmaFile> {
if contains_dir(path.as_ref()) {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Path cannot contain directories",
)
.into());
};
let path = self.file.path_required("open file")?.join(path.as_ref());
DmaFile::open(path).await
}
pub async fn create<P: AsRef<Path>>(path: P) -> Result<Directory> {
let path = path.as_ref().to_owned();
let source = crate::executor().reactor().create_dir(&*path, 0o777).await;
enhanced_try!(
match source.collect_rw().await {
Ok(_) => Ok(()),
Err(x) => {
match x.kind() {
std::io::ErrorKind::AlreadyExists => Ok(()),
_ => Err(x),
}
}
},
"Synchronously creating directory",
Some(&path),
None
)?;
Self::open(&path).await
}
pub async fn create_file<P: AsRef<Path>>(&self, path: P) -> Result<DmaFile> {
if contains_dir(path.as_ref()) {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Path cannot contain directories",
)
.into());
}
let path = self.file.path_required("create file")?.join(path.as_ref());
DmaFile::create(path).await
}
pub fn sync_read_dir(&self) -> Result<std::fs::ReadDir> {
let path = self.file.path_required("read directory")?;
enhanced_try!(std::fs::read_dir(&*path), "Reading a directory", self.file)
.map_err(Into::into)
}
pub async fn sync(&self) -> Result<()> {
let source = self
.file
.reactor
.upgrade()
.unwrap()
.fdatasync(self.as_raw_fd());
source.collect_rw().await?;
Ok(())
}
pub async fn close(self) -> Result<()> {
self.file.close().await
}
pub fn path(&self) -> Option<Ref<'_, Path>> {
self.file.path()
}
}
fn contains_dir(path: &Path) -> bool {
let mut iter = path.components();
match iter.next() {
Some(std::path::Component::Normal(_)) => iter.next().is_some(),
_ => true,
}
}