blob: b8077f9e103bd20da0309cd69be5492b623b9970 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
super::{Filesystem, FilesystemRename},
crate::{directory::helper::DirectlyMutable, path::Path},
async_trait::async_trait,
fuchsia_zircon::Status,
std::{any::Any, marker::PhantomData, sync::Arc},
};
pub struct SimpleFilesystem<T: DirectlyMutable + 'static> {
directory_type: PhantomData<T>,
}
impl<T: DirectlyMutable + 'static> SimpleFilesystem<T> {
pub fn new() -> Self {
SimpleFilesystem { directory_type: PhantomData }
}
}
#[async_trait]
impl<T> FilesystemRename for SimpleFilesystem<T>
where
T: DirectlyMutable + 'static,
{
async fn rename(
&self,
src_dir: Arc<Any + Sync + Send + 'static>,
src: Path,
dst_dir: Arc<Any + Sync + Send + 'static>,
dst: Path,
) -> Result<(), Status> {
let src_parent = src_dir.downcast::<T>().map_err(|_| Status::INVALID_ARGS)?;
let dst_parent = dst_dir.downcast::<T>().map_err(|_| Status::INVALID_ARGS)?;
// We need to lock directories using the same global order, otherwise we risk a deadlock. We
// will use directory objects memory location to establish global order for the locks. It
// introduces additional complexity, but, hopefully, avoids this subtle deadlocking issue.
//
// We will lock first object with the smaller memory address.
let src_order = src_parent.as_ref() as *const dyn DirectlyMutable as *const usize as usize;
let dst_order = dst_parent.as_ref() as *const dyn DirectlyMutable as *const usize as usize;
if src_order < dst_order {
// We must ensure that we have checked the global order for the locks for
// `src_parent` and `dst_parent` and we are calling `rename_from` as `src_parent` has a
// smaller memory address than the `dst_parent`.
src_parent.clone().rename_from(
src.into_string(),
Box::new(move |entry| dst_parent.add_entry_impl(dst.into_string(), entry, true)),
)
} else if src_order == dst_order {
src_parent.rename_within(src.into_string(), dst.into_string())
} else {
// We must ensure that we have checked the global order for the locks for
// `src_parent` and `dst_parent` and we are calling `rename_to` as `dst_parent` has a
// smaller memory address than the `src_parent`.
dst_parent.rename_to(
dst.into_string(),
Box::new(move || match src_parent.remove_entry_impl(src.into_string(), false)? {
None => Err(Status::NOT_FOUND),
Some(entry) => Ok(entry),
}),
)
}
}
}
impl<T> Filesystem for SimpleFilesystem<T>
where
T: DirectlyMutable + 'static,
{
/// Returns the size of the Filesystem's block device. This is the granularity at which I/O is
/// performed.
fn block_size(&self) -> u32 {
1
}
}