use super::*;
pub struct FsDir<F: VectorBackend> {
pub(super) inner: Arc<SharedBackend<F>>,
pub(super) dir: Option<VfDir>,
pub(super) path: PathBuf,
}
impl<F: VectorBackend> fmt::Debug for FsDir<F> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("FsDir")
.field("path", &self.path)
.finish_non_exhaustive()
}
}
impl<F: VectorBackend> FsDir<F> {
pub fn is_closed(&self) -> bool {
self.dir.is_none()
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn close(mut self) -> VfResult<()> {
self.try_close()
}
pub fn try_close(&mut self) -> VfResult<()> {
let Some(dir) = self.dir.as_ref() else {
return Ok(());
};
self.inner
.lock()
.map_err(|_| poisoned())?
.close_dir_impl(dir)?;
self.dir = None;
Ok(())
}
}
impl<F: VectorBackend> Drop for FsDir<F> {
fn drop(&mut self) {
if let Some(dir) = self.dir.take() {
self.inner.defer(
CleanupTarget::Directory(dir, std::mem::take(&mut self.path)),
|backend, target| {
let CleanupTarget::Directory(dir, path) = target else {
unreachable!()
};
backend
.close_dir_impl(dir)
.map_err(|error| error.with_context("close_dir", path))
},
);
}
}
}
pub struct OpenFile<F: HandleBackend> {
pub(super) inner: Arc<SharedBackend<F>>,
pub(super) file: Option<FileOperand>,
pub(super) append: bool,
pub(super) path: PathBuf,
}
impl<F: HandleBackend> fmt::Debug for OpenFile<F> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("OpenFile")
.field("path", &self.path)
.field("is_open", &self.file.is_some())
.finish()
}
}
impl<F: HandleBackend> OpenFile<F> {
pub fn is_closed(&self) -> bool {
self.file.is_none()
}
pub(super) fn raw(&self) -> VfResult<&FileOperand> {
self.file
.as_ref()
.ok_or_else(|| VfError::client(0, crate::ERR_EBADF))
}
pub fn read_request_at(&self, offset: u64, length: usize) -> FsRead<'_, F> {
FsRead {
file: self,
offset: VfOffset::At(offset),
length,
}
}
pub fn path(&self) -> &Path {
&self.path
}
pub fn write_request_at<'a>(&'a self, offset: u64, data: &'a [u8]) -> FsWrite<'a, F> {
FsWrite::new(self, VfOffset::At(offset), data)
}
pub fn read_request_at_into<'a>(
&'a self,
offset: u64,
buffer: &'a mut [u8],
) -> FsReadInto<'a, F> {
FsReadInto {
file: self,
offset: VfOffset::At(offset),
buffer,
}
}
pub fn try_close(&mut self) -> VfResult<()> {
let Some(file) = self.file.as_ref() else {
return Ok(());
};
self.inner
.lock()
.map_err(|_| poisoned())?
.close_impl(file)
.map_err(|error| error.with_context("close", &self.path))?;
self.file = None;
Ok(())
}
pub fn close(mut self) -> VfResult<()> {
self.try_close()
}
}
pub struct FsRead<'a, F: HandleBackend> {
pub(super) file: &'a OpenFile<F>,
pub(super) offset: VfOffset,
pub(super) length: usize,
}
pub type FsWrite<'a, F> =
vfsi_core::internal::WriteRequest<&'a OpenFile<F>, &'a [u8], VfOffset, ()>;
pub struct FsReadInto<'a, F: HandleBackend> {
pub(super) file: &'a OpenFile<F>,
pub(super) offset: VfOffset,
pub(super) buffer: &'a mut [u8],
}
impl<F: HandleBackend> Drop for OpenFile<F> {
fn drop(&mut self) {
if let Some(file) = self.file.take() {
self.inner.defer(
CleanupTarget::File(file, std::mem::take(&mut self.path)),
|backend, target| {
let CleanupTarget::File(file, path) = target else {
unreachable!()
};
backend
.close_deferred(file)
.map_err(|error| error.with_context("close", path))
},
);
}
}
}