use std::{array::TryFromSliceError, fmt};
#[derive(Debug)]
pub enum BackupError {
Io(std::io::Error),
Database(rusqlite::Error),
DatabaseClosed,
Crypto(String),
ConversionFailed(TryFromSliceError),
NotEncrypted,
PasswordOrKeyRequired,
PasswordOrKeyIncorrect,
ManifestPlistNotFound(String),
ManifestDbNotFound,
FileNotFoundInBackup(String),
InvalidBackupRoot(String),
DeviceNotFound(String),
HexDecode(String),
Utf8(std::string::FromUtf8Error),
General(String),
MissingPlistKey(String),
KeyUnwrapFailed(u32),
InvalidCryptoDataLength {
expected: usize,
actual: usize,
},
InvalidTlvData(String),
PlistParseError(String),
}
pub type Result<T> = std::result::Result<T, BackupError>;
impl fmt::Display for BackupError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BackupError::Io(err) => write!(f, "IO error: {err}"),
BackupError::Database(err) => write!(f, "SQLite database error: {err}"),
BackupError::DatabaseClosed => write!(f, "Manifest.db was already closed!"),
BackupError::Crypto(msg) => write!(f, "Cryptography error: {msg}"),
BackupError::ConversionFailed(why) => {
write!(f, "Conversion failed: {why}")
}
BackupError::NotEncrypted => write!(f, "Backup is not encrypted"),
BackupError::PasswordOrKeyRequired => write!(
f,
"Password or derived key is required for encrypted backups"
),
BackupError::PasswordOrKeyIncorrect => {
write!(f, "Password or derived key is incorrect")
}
BackupError::ManifestPlistNotFound(path) => {
write!(f, "Manifest.plist not found at {path}")
}
BackupError::ManifestDbNotFound => {
write!(f, "Manifest.db not found or could not be decrypted")
}
BackupError::FileNotFoundInBackup(path) => {
write!(f, "File not found in backup: {path}")
}
BackupError::InvalidBackupRoot(path) => write!(f, "Invalid backup root: {path}"),
BackupError::DeviceNotFound(udid) => write!(f, "Device not found: {udid}"),
BackupError::HexDecode(msg) => write!(f, "Hex decoding error: {msg}"),
BackupError::Utf8(err) => write!(f, "UTF-8 conversion error: {err}"),
BackupError::General(msg) => write!(f, "General backup error: {msg}"),
BackupError::MissingPlistKey(key) => {
write!(f, "Missing required key in Manifest.plist: {key}")
}
BackupError::KeyUnwrapFailed(class_id) => {
write!(f, "Key unwrapping failed for class {class_id}")
}
BackupError::InvalidCryptoDataLength { expected, actual } => write!(
f,
"Invalid data length for cryptographic operation: expected {expected}, got {actual}"
),
BackupError::InvalidTlvData(msg) => write!(f, "Invalid TLV data: {msg}"),
BackupError::PlistParseError(msg) => write!(f, "Plist parse error: {msg}"),
}
}
}
impl std::error::Error for BackupError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
BackupError::Io(err) => Some(err),
BackupError::Database(err) => Some(err),
BackupError::Utf8(err) => Some(err),
_ => None,
}
}
}
impl From<std::io::Error> for BackupError {
fn from(err: std::io::Error) -> Self {
BackupError::Io(err)
}
}
impl From<rusqlite::Error> for BackupError {
fn from(err: rusqlite::Error) -> Self {
BackupError::Database(err)
}
}
impl From<std::string::FromUtf8Error> for BackupError {
fn from(err: std::string::FromUtf8Error) -> Self {
BackupError::Utf8(err)
}
}