use std::io;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use fs_mistrust::CheckedDir;
use tor_error::{ErrorKind, HasKind};
use tor_key_forge::KeystoreItemType;
use crate::{ArtiPathUnavailableError, KeySpecifier};
#[derive(Debug, Clone)]
pub(super) struct RelKeyPath<'a> {
dir: &'a CheckedDir,
path: PathBuf,
}
impl<'a> RelKeyPath<'a> {
pub(super) fn arti(
dir: &'a CheckedDir,
key_spec: &dyn KeySpecifier,
item_type: &KeystoreItemType,
) -> Result<Self, ArtiPathUnavailableError> {
let arti_path: String = key_spec.arti_path()?.into();
let mut path = PathBuf::from(arti_path);
path.set_extension(item_type.arti_extension());
Ok(Self { dir, path })
}
#[cfg(feature = "ctor-keystore")]
pub(super) fn from_parts(dir: &'a CheckedDir, path: PathBuf) -> Self {
Self { dir, path }
}
pub(super) fn checked_path(&self) -> Result<PathBuf, FilesystemError> {
let abs_path = self
.dir
.join(&self.path)
.map_err(|err| FilesystemError::FsMistrust {
action: FilesystemAction::Read,
path: self.path.clone(),
err: err.into(),
})?;
Ok(abs_path)
}
pub(super) fn rel_path_unchecked(&self) -> &Path {
&self.path
}
pub(super) fn checked_dir(&self) -> &CheckedDir {
self.dir
}
}
pub(crate) use internal::checked_op;
mod internal {
macro_rules! checked_op {
($op:ident, $relpath:expr $(, $arg:expr)* ) => {{
$relpath.checked_dir().$op($relpath.rel_path_unchecked(), $($arg,)* )
}}
}
pub(crate) use checked_op;
}
#[derive(thiserror::Error, Debug, Clone)]
pub(crate) enum FilesystemError {
#[error("IO error on {path} while attempting to {action}")]
Io {
action: FilesystemAction,
path: PathBuf,
#[source]
err: Arc<io::Error>,
},
#[error("Inaccessible path or bad permissions on {path} while attempting to {action}")]
FsMistrust {
action: FilesystemAction,
path: PathBuf,
#[source]
err: Arc<fs_mistrust::Error>,
},
#[error("File at {0} is not a regular file")]
NotARegularFile(PathBuf),
}
#[derive(Copy, Clone, Debug, derive_more::Display)]
pub(crate) enum FilesystemAction {
Init,
Read,
Write,
Remove,
}
impl HasKind for FilesystemError {
fn kind(&self) -> ErrorKind {
use FilesystemError as FE;
use tor_persist::FsMistrustErrorExt as _;
match self {
FE::Io { .. } => ErrorKind::KeystoreAccessFailed,
FE::FsMistrust { err, .. } => err.keystore_error_kind(),
FE::NotARegularFile(_) => ErrorKind::KeystoreCorrupted,
}
}
}