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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
use crate::ArchiveFileID;
use hkdf::InvalidLength;
use std::error;
use std::fmt;
use std::io;
#[derive(Debug)]
pub enum Error {
/// IO Error (not enough data, etc.)
IOError(io::Error),
/// Wrong magic, must be "MLA"
WrongMagic,
/// Unsupported version, must be 1
UnsupportedVersion,
/// Supplied ECC key is not in the expected format
InvalidECCKeyFormat,
/// Wrong BlockSubFile magic has been encountered. Is the deserializion
/// starting at the beginning of a block?
WrongBlockSubFileType,
/// An error has occurred while converting into UTF8. This error could
/// happens while parsing the block filename
UTF8ConversionError(std::string::FromUtf8Error),
/// Filenames have a limited size `FILENAME_MAX_SIZE`
FilenameTooLong,
/// The writer state is not in the expected state for the current operation
WrongArchiveWriterState {
current_state: String,
expected_state: String,
},
/// Should never happens: an internal assumptions no more hold
AssertionError(String),
/// The reader state is not in the expected state for the current operation
WrongReaderState(String),
/// The writer state is not in the expected state for the current operation
WrongWriterState(String),
/// Error with the inner random generator
RandError(rand::Error),
/// A Private Key is required to decrypt the encrypted cipher key
PrivateKeyNeeded,
/// Deserialization error. May happens when starting from a wrong offset /
/// version mismatch
DeserializationError,
/// Serialization error. May happens on I/O errors
SerializationError,
/// Missing metadata (usually means the footer has not been correctly read,
/// a repair might be needed)
MissingMetadata,
/// Error returned on API call with incorrect argument
BadAPIArgument(String),
/// End of stream reached, no more data should be expected
EndOfStream,
/// An error happens in the configuration
ConfigError(ConfigError),
/// Filename already used
DuplicateFilename,
/// Wrong tag while decrypting authenticated data
AuthenticatedDecryptionWrongTag,
/// Unable to expand while using the HKDF
HKDFInvalidKeyLength,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// For now, use the debug derived version
write!(f, "{:?}", self)
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Error::IOError(error)
}
}
impl From<std::string::FromUtf8Error> for Error {
fn from(error: std::string::FromUtf8Error) -> Self {
Error::UTF8ConversionError(error)
}
}
impl From<rand::Error> for Error {
fn from(error: rand::Error) -> Self {
Error::RandError(error)
}
}
impl From<bincode::ErrorKind> for Error {
fn from(_error: bincode::ErrorKind) -> Self {
Error::DeserializationError
}
}
impl From<Error> for io::Error {
fn from(error: Error) -> Self {
io::Error::new(io::ErrorKind::Other, format!("{}", error))
}
}
impl From<ConfigError> for Error {
fn from(error: ConfigError) -> Self {
match error {
ConfigError::PrivateKeyNotSet => Error::PrivateKeyNeeded,
_ => Error::ConfigError(error),
}
}
}
impl From<InvalidLength> for Error {
fn from(_error: InvalidLength) -> Self {
Error::HKDFInvalidKeyLength
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match &self {
Error::IOError(err) => Some(err),
Error::UTF8ConversionError(err) => Some(err),
Error::RandError(err) => Some(err),
Error::ConfigError(err) => Some(err),
_ => None,
}
}
}
#[derive(Debug)]
pub enum FailSafeReadError {
/// Everything ends correctly
NoError,
/// An unexpected EOF occurs while getting the next block
UnexpectedEOFOnNextBlock,
/// An IO error occurs while reading the next block
IOErrorOnNextBlock(io::Error),
/// A Error occurs while reading the next block
ErrorOnNextBlock(Error),
/// An error occurs in the middle of a file
ErrorInFile(io::Error, String),
/// A file ID is being reused
ArchiveFileIDReuse(ArchiveFileID),
/// A filename is being reused
FilenameReuse(String),
/// Data for a file already closed
ArchiveFileIDAlreadyClose(ArchiveFileID),
/// Content for an unknown file
ContentForUnknownFile(ArchiveFileID),
/// Termination of an unknwown file
EOFForUnknownFile(ArchiveFileID),
/// Wraps an already existing error and indicates which files are not
/// finished (a file can be finished but uncompleted)
UnfinishedFiles {
filenames: Vec<String>,
stopping_error: Box<FailSafeReadError>,
},
/// End of original archive reached - this is the best case
EndOfOriginalArchiveData,
/// Error in the FailSafeReader internal state
FailSafeReadInternalError,
/// The file's hash does not correspond to the expected one
HashDiffers {
expected: Vec<u8>,
obtained: Vec<u8>,
},
}
impl fmt::Display for FailSafeReadError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// For now, use the debug derived version
write!(f, "{:?}", self)
}
}
impl error::Error for FailSafeReadError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match &self {
FailSafeReadError::IOErrorOnNextBlock(err) => Some(err),
FailSafeReadError::ErrorOnNextBlock(err) => Some(err),
FailSafeReadError::ErrorInFile(err, _path) => Some(err),
_ => None,
}
}
}
#[derive(Debug)]
pub enum ConfigError {
IncoherentPersistentConfig,
// Compression specifics
CompressionLevelOutOfRange,
// Encryption specifics
EncryptionKeyIsMissing,
PrivateKeyNotSet,
PrivateKeyNotFound,
ECIESComputationError,
}
impl fmt::Display for ConfigError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// For now, use the debug derived version
write!(f, "{:?}", self)
}
}
impl error::Error for ConfigError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}