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
//! Error type returned across the crate.
use std::fmt;
/// An error from opening, parsing, or extracting an ALZ archive.
#[derive(Debug)]
pub enum AlzError {
/// The input does not start with an ALZ signature.
NotAlzFile,
/// A header or field is malformed or inconsistent.
CorruptedFile,
/// The archive file (or a volume) could not be opened.
CantOpenFile(std::io::Error),
/// The destination file could not be created or written.
CantOpenDestFile(std::io::Error),
/// A local file header declares an out-of-range filename length.
InvalidFilenameLength,
/// DEFLATE decompression failed.
InflateFailed(String),
/// bzip2 decompression failed.
Bzip2Failed(String),
/// The decompressed data does not match the stored CRC32.
InvalidFileCrc {
/// CRC32 stored in the archive.
expected: u32,
/// CRC32 of the decompressed data.
got: u32,
},
/// The size-field width bits in a file descriptor are not 0/1/2/4/8 bytes.
InvalidSizeFieldWidth(u8),
/// The entry uses a compression method this extractor does not support.
UnknownCompressionMethod(u8),
/// Decompression produced more than the declared uncompressed size.
UncompressedSizeExceeded {
/// The declared uncompressed size that was exceeded.
limit: u64,
},
/// The entry count exceeds what the archive size could hold.
TooManyEntries,
/// An encrypted entry was reached without a password.
PasswordNotSet,
/// The password failed the encryption header check.
InvalidPassword,
/// An entry name or symlink target would escape the destination directory.
PathTraversal(String),
/// An underlying I/O error.
Io(std::io::Error),
}
impl fmt::Display for AlzError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NotAlzFile => write!(f, "not an ALZ file"),
Self::CorruptedFile => write!(f, "corrupted file"),
Self::CantOpenFile(e) => write!(f, "can't open archive file: {e}"),
Self::CantOpenDestFile(e) => write!(f, "can't open dest file: {e}"),
Self::InvalidFilenameLength => write!(f, "invalid filename length"),
Self::InflateFailed(s) => write!(f, "inflate failed: {s}"),
Self::Bzip2Failed(s) => write!(f, "bzip2 decompress failed: {s}"),
Self::InvalidFileCrc { expected, got } => {
write!(
f,
"invalid file CRC: expected {expected:08x}, got {got:08x}"
)
}
Self::InvalidSizeFieldWidth(v) => {
write!(f, "invalid size field width: 0x{v:02x}")
}
Self::UnknownCompressionMethod(m) => write!(f, "unknown compression method: {m}"),
Self::UncompressedSizeExceeded { limit } => {
write!(
f,
"decompressed output exceeds declared size ({limit} bytes)"
)
}
Self::TooManyEntries => write!(f, "too many file entries for archive size"),
Self::PasswordNotSet => write!(f, "password was not set"),
Self::InvalidPassword => write!(f, "invalid password"),
Self::PathTraversal(p) => write!(f, "path traversal blocked: {p}"),
Self::Io(e) => write!(f, "{e}"),
}
}
}
impl std::error::Error for AlzError {}
impl From<std::io::Error> for AlzError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
pub type AlzResult<T> = Result<T, AlzError>;