1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
//! Module providing support for handling paths relative to a [`CheckedDir`].
//!
//! The underlying relative path of a [`RelKeyPath`] should not be manipulated directly.
//! Instead, prefer converting it to an absolute path using
//! [`checked_path`](RelKeyPath::checked_path) where possible.
//! You may also use the `checked_op` macro to call [`CheckedDir`] functions on the path.
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};
/// The path of a key, relative to a [`CheckedDir`].
///
/// See the [module-level documentation](self) for a general overview.
#[derive(Debug, Clone)]
pub(super) struct RelKeyPath<'a> {
/// The directory this path is relative to.
dir: &'a CheckedDir,
/// The relative path.
path: PathBuf,
}
impl<'a> RelKeyPath<'a> {
/// Create a new [`RelKeyPath`] representing an `ArtiPath`.
///
/// Returns an error if `key_spec` does not have an `ArtiPath`.
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 })
}
/// Create a new [`RelKeyPath`] from a `CheckedDir` and a relative path.
#[cfg(feature = "ctor-keystore")]
pub(super) fn from_parts(dir: &'a CheckedDir, path: PathBuf) -> Self {
Self { dir, path }
}
/// Return the checked absolute 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)
}
/// Return this as an unchecked relative path.
pub(super) fn rel_path_unchecked(&self) -> &Path {
&self.path
}
/// Return the [`CheckedDir`] of this `RelKeyPath`.
pub(super) fn checked_dir(&self) -> &CheckedDir {
self.dir
}
}
pub(crate) use internal::checked_op;
/// Private module for reexporting the `checked_op` macro.
mod internal {
/// Run operation `op` on a [`RelKeyPath`](super::RelKeyPath).
///
/// `op` is an identifier that represents a [`CheckedDir`](fs_mistrust::CheckedDir) function.
macro_rules! checked_op {
($op:ident, $relpath:expr $(, $arg:expr)* ) => {{
$relpath.checked_dir().$op($relpath.rel_path_unchecked(), $($arg,)* )
}}
}
pub(crate) use checked_op;
}
/// An error that occurred while accessing the filesystem.
#[derive(thiserror::Error, Debug, Clone)]
pub(crate) enum FilesystemError {
/// An IO error that occurred while accessing the filesystem.
#[error("IO error on {path} while attempting to {action}")]
Io {
/// The action we were trying to perform.
action: FilesystemAction,
/// The path of the key we were trying to fetch.
path: PathBuf,
/// The underlying error.
#[source]
err: Arc<io::Error>,
},
/// Encountered an inaccessible path or invalid permissions.
#[error("Inaccessible path or bad permissions on {path} while attempting to {action}")]
FsMistrust {
/// The action we were trying to perform.
action: FilesystemAction,
/// The path of the key we were trying to fetch.
path: PathBuf,
/// The underlying error.
#[source]
err: Arc<fs_mistrust::Error>,
},
/// An error due to encountering a directory or symlink at a key path.
#[error("File at {0} is not a regular file")]
NotARegularFile(PathBuf),
}
/// The action that caused a [`FilesystemError`].
#[derive(Copy, Clone, Debug, derive_more::Display)]
pub(crate) enum FilesystemAction {
/// Filesystem key store initialization.
Init,
/// Filesystem read
Read,
/// Filesystem write
Write,
/// Filesystem remove
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,
}
}
}
|