diff options
| author | igorechek06 <me@igorek.dev> | 2024-08-10 17:58:14 +0900 |
|---|---|---|
| committer | igorechek06 <me@igorek.dev> | 2024-08-10 17:58:14 +0900 |
| commit | 1bb400dcb258f135a3f92f6242e728f0475325c1 (patch) | |
| tree | c71783ceaff073077b7f65705101932ca8f0bbf6 | |
| parent | 866516ac50851e2827e6aff0a98c444268c566ff (diff) | |
| download | archivator-1bb400dcb258f135a3f92f6242e728f0475325c1.tar.gz archivator-1bb400dcb258f135a3f92f6242e728f0475325c1.zip | |
Unify zip errors
| -rw-r--r-- | src/zip/datetime.rs | 4 | ||||
| -rw-r--r-- | src/zip/driver.rs | 16 | ||||
| -rw-r--r-- | src/zip/error.rs | 68 | ||||
| -rw-r--r-- | src/zip/file/info.rs | 4 | ||||
| -rw-r--r-- | src/zip/file/read.rs | 14 | ||||
| -rw-r--r-- | tests/zip.rs | 2 |
6 files changed, 43 insertions, 65 deletions
diff --git a/src/zip/datetime.rs b/src/zip/datetime.rs index a4b1b55..e101334 100644 --- a/src/zip/datetime.rs +++ b/src/zip/datetime.rs | |||
| @@ -18,13 +18,13 @@ impl<Tz: TimeZone> DosDateTime<Tz> for DateTime<Tz> { | |||
| 18 | date as u32 >> 5 & 0xF, | 18 | date as u32 >> 5 & 0xF, |
| 19 | date as u32 & 0x1F, | 19 | date as u32 & 0x1F, |
| 20 | ) | 20 | ) |
| 21 | .ok_or(ZipError::InvalidDate)? | 21 | .ok_or(ZipError::InvalidField("date"))? |
| 22 | .and_hms_opt( | 22 | .and_hms_opt( |
| 23 | (time as u32 >> 11) & 0x1F, | 23 | (time as u32 >> 11) & 0x1F, |
| 24 | (time as u32 >> 5) & 0x3F, | 24 | (time as u32 >> 5) & 0x3F, |
| 25 | (time as u32 & 0x1F) * 2, | 25 | (time as u32 & 0x1F) * 2, |
| 26 | ) | 26 | ) |
| 27 | .ok_or(ZipError::InvalidTime)? | 27 | .ok_or(ZipError::InvalidField("time"))? |
| 28 | .and_local_timezone(tz) | 28 | .and_local_timezone(tz) |
| 29 | .unwrap()) | 29 | .unwrap()) |
| 30 | } | 30 | } |
diff --git a/src/zip/driver.rs b/src/zip/driver.rs index 9dccfd0..81629dd 100644 --- a/src/zip/driver.rs +++ b/src/zip/driver.rs | |||
| @@ -83,11 +83,11 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 83 | + io.read_vec( | 83 | + io.read_vec( |
| 84 | (limit as usize) | 84 | (limit as usize) |
| 85 | .checked_sub(18) | 85 | .checked_sub(18) |
| 86 | .ok_or(ZipError::EocdrNotFound)?, | 86 | .ok_or(ZipError::StructNotFound("Eocdr"))?, |
| 87 | )? | 87 | )? |
| 88 | .windows(4) | 88 | .windows(4) |
| 89 | .rposition(|v| v == EOCDR_SIGNATURE) | 89 | .rposition(|v| v == EOCDR_SIGNATURE) |
| 90 | .ok_or(ZipError::EocdrNotFound)? as u64; | 90 | .ok_or(ZipError::StructNotFound("Eocdr"))? as u64; |
| 91 | 91 | ||
| 92 | // Read eocdr | 92 | // Read eocdr |
| 93 | io.seek(SeekFrom::Start(pos + 4))?; | 93 | io.seek(SeekFrom::Start(pos + 4))?; |
| @@ -106,7 +106,7 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 106 | io.seek(SeekFrom::Start(eocdr64locator.eocdr64_pointer))?; | 106 | io.seek(SeekFrom::Start(eocdr64locator.eocdr64_pointer))?; |
| 107 | let buf = io.read_arr::<56>()?; | 107 | let buf = io.read_arr::<56>()?; |
| 108 | if buf[0..4] != EOCDR64_SIGNATURE { | 108 | if buf[0..4] != EOCDR64_SIGNATURE { |
| 109 | return Err(ZipError::InvalidEocdr64Signature); | 109 | return Err(ZipError::InvalidSignature("Eocdr64")); |
| 110 | } | 110 | } |
| 111 | let eocdr64: Eocdr64 = deserialize(&buf[4..]).unwrap(); | 111 | let eocdr64: Eocdr64 = deserialize(&buf[4..]).unwrap(); |
| 112 | if eocdr64.cd_pointer + eocdr64.cd_size > eocdr64locator.eocdr64_pointer { | 112 | if eocdr64.cd_pointer + eocdr64.cd_size > eocdr64locator.eocdr64_pointer { |
| @@ -139,14 +139,14 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 139 | let buf = cd_reader.read_arr::<46>()?; | 139 | let buf = cd_reader.read_arr::<46>()?; |
| 140 | 140 | ||
| 141 | if buf[..4] != CDR_SIGNATURE { | 141 | if buf[..4] != CDR_SIGNATURE { |
| 142 | return Err(ZipError::InvalidCdrSignature); | 142 | return Err(ZipError::InvalidSignature("Cdr")); |
| 143 | } | 143 | } |
| 144 | let cdr: Cdr = deserialize(&buf[4..46]).unwrap(); | 144 | let cdr: Cdr = deserialize(&buf[4..46]).unwrap(); |
| 145 | let bit_flag = BitFlag::new(cdr.bit_flag); | 145 | let bit_flag = BitFlag::new(cdr.bit_flag); |
| 146 | 146 | ||
| 147 | let name = cd_reader.read_vec(cdr.name_len as usize)?; | 147 | let name = cd_reader.read_vec(cdr.name_len as usize)?; |
| 148 | let name = if bit_flag.is_utf8() { | 148 | let name = if bit_flag.is_utf8() { |
| 149 | String::from_utf8(name).map_err(|_| ZipError::InvalidFileName)? | 149 | String::from_utf8(name).map_err(|_| ZipError::InvalidField("file_name"))? |
| 150 | } else { | 150 | } else { |
| 151 | String::from_cp437(name) | 151 | String::from_cp437(name) |
| 152 | }; | 152 | }; |
| @@ -155,7 +155,7 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 155 | 155 | ||
| 156 | let comment = cd_reader.read_vec(cdr.comment_len as usize)?; | 156 | let comment = cd_reader.read_vec(cdr.comment_len as usize)?; |
| 157 | let comment = if bit_flag.is_utf8() { | 157 | let comment = if bit_flag.is_utf8() { |
| 158 | String::from_utf8(comment).map_err(|_| ZipError::InvalidFileComment)? | 158 | String::from_utf8(comment).map_err(|_| ZipError::InvalidField("file_comment"))? |
| 159 | } else { | 159 | } else { |
| 160 | String::from_cp437(comment) | 160 | String::from_cp437(comment) |
| 161 | }; | 161 | }; |
| @@ -216,7 +216,7 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 216 | 0x9901 => { | 216 | 0x9901 => { |
| 217 | let aes: AesField = deserialize(&data.read_arr::<7>()?).unwrap(); | 217 | let aes: AesField = deserialize(&data.read_arr::<7>()?).unwrap(); |
| 218 | if aes.id != [0x41, 0x45] { | 218 | if aes.id != [0x41, 0x45] { |
| 219 | return Err(ZipError::InvalidExtraFields); | 219 | return Err(ZipError::InvalidField("extra_fields")); |
| 220 | } | 220 | } |
| 221 | encryption_method = match aes.strength { | 221 | encryption_method = match aes.strength { |
| 222 | 0x01 => EncryptionMethod::Aes128, | 222 | 0x01 => EncryptionMethod::Aes128, |
| @@ -232,7 +232,7 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | if compression_method == 99 { | 234 | if compression_method == 99 { |
| 235 | return Err(ZipError::AesExtraFieldNotFound); | 235 | return Err(ZipError::StructNotFound("AesExtensibleData")); |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | indexes.insert(name.clone(), i); | 238 | indexes.insert(name.clone(), i); |
diff --git a/src/zip/error.rs b/src/zip/error.rs index dbb6bb5..fbc2ba1 100644 --- a/src/zip/error.rs +++ b/src/zip/error.rs | |||
| @@ -8,27 +8,18 @@ pub type ZipResult<T> = Result<T, ZipError>; | |||
| 8 | pub enum ZipError { | 8 | pub enum ZipError { |
| 9 | Io(IoError), | 9 | Io(IoError), |
| 10 | 10 | ||
| 11 | EocdrNotFound, | 11 | // Driver errors |
| 12 | InvalidEocdr64Signature, | 12 | StructNotFound(&'static str), |
| 13 | InvalidFileHeaderSignature, | 13 | InvalidSignature(&'static str), |
| 14 | InvalidCdrSignature, | 14 | InvalidField(&'static str), |
| 15 | 15 | Unsupported(&'static str), | |
| 16 | Overlapping(&'static str, &'static str), | 16 | Overlapping(&'static str, &'static str), |
| 17 | 17 | ||
| 18 | UnsupportedCompressionMethod(u16), | 18 | // API errors |
| 19 | UnsupportedEncryptionMethod, | ||
| 20 | InvalidDate, | ||
| 21 | InvalidTime, | ||
| 22 | InvalidFileName, | ||
| 23 | InvalidExtraFields, | ||
| 24 | AesExtraFieldNotFound, | ||
| 25 | InvalidFileComment, | ||
| 26 | |||
| 27 | FileNotFound, | 19 | FileNotFound, |
| 28 | WrongPassword, | 20 | WrongPassword, |
| 29 | PasswordIsNotSpecified, | 21 | PasswordIsNotSpecified, |
| 30 | CompressedDataIsUnseekable, | 22 | UnseekableFile, |
| 31 | EncryptedDataIsUnseekable, | ||
| 32 | } | 23 | } |
| 33 | 24 | ||
| 34 | impl From<IoError> for ZipError { | 25 | impl From<IoError> for ZipError { |
| @@ -41,9 +32,10 @@ impl PartialEq for ZipError { | |||
| 41 | fn eq(&self, other: &Self) -> bool { | 32 | fn eq(&self, other: &Self) -> bool { |
| 42 | match (self, other) { | 33 | match (self, other) { |
| 43 | (Self::Io(l0), Self::Io(r0)) => l0.kind() == r0.kind(), | 34 | (Self::Io(l0), Self::Io(r0)) => l0.kind() == r0.kind(), |
| 44 | (Self::UnsupportedCompressionMethod(l0), Self::UnsupportedCompressionMethod(r0)) => { | 35 | (Self::StructNotFound(l0), Self::StructNotFound(r0)) => l0 == r0, |
| 45 | l0 == r0 | 36 | (Self::InvalidSignature(l0), Self::InvalidSignature(r0)) => l0 == r0, |
| 46 | } | 37 | (Self::InvalidField(l0), Self::InvalidField(r0)) => l0 == r0, |
| 38 | (Self::Overlapping(l0, l1), Self::Overlapping(r0, r1)) => l0 == r0 && l1 == r1, | ||
| 47 | _ => core::mem::discriminant(self) == core::mem::discriminant(other), | 39 | _ => core::mem::discriminant(self) == core::mem::discriminant(other), |
| 48 | } | 40 | } |
| 49 | } | 41 | } |
| @@ -56,42 +48,26 @@ impl Display for ZipError { | |||
| 56 | match self { | 48 | match self { |
| 57 | Self::Io(error) => write!(f, "{}", error), | 49 | Self::Io(error) => write!(f, "{}", error), |
| 58 | 50 | ||
| 59 | Self::EocdrNotFound => write!(f, "End of central directory record not found"), | 51 | Self::StructNotFound(struct_name) => { |
| 60 | Self::InvalidEocdr64Signature => { | 52 | write!(f, "Struct '{}' not found", struct_name) |
| 61 | write!( | ||
| 62 | f, | ||
| 63 | "Invalid signature of zip64 end of central directory record" | ||
| 64 | ) | ||
| 65 | } | 53 | } |
| 66 | Self::InvalidFileHeaderSignature => { | 54 | Self::InvalidSignature(struct_name) => { |
| 67 | write!(f, "Invalid file header signature") | 55 | write!(f, "Invalid signature of struct '{}'", struct_name) |
| 68 | } | 56 | } |
| 69 | Self::InvalidCdrSignature => { | 57 | Self::InvalidField(field_name) => { |
| 70 | write!(f, "Invalid signature of central directory record") | 58 | write!(f, "Field '{}' has invalid data", field_name) |
| 71 | } | 59 | } |
| 72 | 60 | Self::Unsupported(data_type) => { | |
| 73 | Self::Overlapping(struct1, struct2) => { | 61 | writeln!(f, "Unsupported {}", data_type) |
| 74 | write!(f, "`{}` overlapt `{}`", struct1, struct2) | ||
| 75 | } | ||
| 76 | |||
| 77 | Self::UnsupportedCompressionMethod(id) => { | ||
| 78 | writeln!(f, "Unsupported compression method `{}`", id) | ||
| 79 | } | 62 | } |
| 80 | Self::UnsupportedEncryptionMethod => { | 63 | Self::Overlapping(struct_name1, struct_name2) => { |
| 81 | writeln!(f, "Unsupported encryption method") | 64 | write!(f, "`{}` overlap `{}`", struct_name1, struct_name2) |
| 82 | } | 65 | } |
| 83 | Self::InvalidDate => write!(f, "Invalid date"), | ||
| 84 | Self::InvalidTime => write!(f, "Invalid time"), | ||
| 85 | Self::InvalidFileName => write!(f, "Invalid file name"), | ||
| 86 | Self::InvalidExtraFields => write!(f, "Invalid extra fields"), | ||
| 87 | Self::AesExtraFieldNotFound => write!(f, "Aes extra field not found"), | ||
| 88 | Self::InvalidFileComment => write!(f, "Invalid file comment"), | ||
| 89 | 66 | ||
| 90 | Self::FileNotFound => write!(f, "File not found"), | 67 | Self::FileNotFound => write!(f, "File not found"), |
| 91 | Self::WrongPassword => write!(f, "Wrong password"), | 68 | Self::WrongPassword => write!(f, "Wrong password"), |
| 92 | Self::PasswordIsNotSpecified => write!(f, "Password is not specified"), | 69 | Self::PasswordIsNotSpecified => write!(f, "Password is not specified"), |
| 93 | Self::CompressedDataIsUnseekable => write!(f, "Compressed data is unseekable"), | 70 | Self::UnseekableFile => write!(f, "File is unseekable"), |
| 94 | Self::EncryptedDataIsUnseekable => write!(f, "Encrypted data is unseekable"), | ||
| 95 | } | 71 | } |
| 96 | } | 72 | } |
| 97 | } | 73 | } |
diff --git a/src/zip/file/info.rs b/src/zip/file/info.rs index 38ea984..93b9f43 100644 --- a/src/zip/file/info.rs +++ b/src/zip/file/info.rs | |||
| @@ -10,7 +10,7 @@ pub enum CompressionMethod { | |||
| 10 | Lzma, | 10 | Lzma, |
| 11 | Zstd, | 11 | Zstd, |
| 12 | Xz, | 12 | Xz, |
| 13 | Unsupported(u16), | 13 | Unsupported, |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | impl CompressionMethod { | 16 | impl CompressionMethod { |
| @@ -23,7 +23,7 @@ impl CompressionMethod { | |||
| 23 | 14 => Self::Lzma, | 23 | 14 => Self::Lzma, |
| 24 | 93 => Self::Zstd, | 24 | 93 => Self::Zstd, |
| 25 | 95 => Self::Xz, | 25 | 95 => Self::Xz, |
| 26 | _ => Self::Unsupported(id), | 26 | _ => Self::Unsupported, |
| 27 | } | 27 | } |
| 28 | } | 28 | } |
| 29 | } | 29 | } |
diff --git a/src/zip/file/read.rs b/src/zip/file/read.rs index d25655e..567fb75 100644 --- a/src/zip/file/read.rs +++ b/src/zip/file/read.rs | |||
| @@ -116,7 +116,9 @@ impl<Io: Read + Seek> Encryption<IoCursor<Io>> { | |||
| 116 | Aes256::new(key.into()), | 116 | Aes256::new(key.into()), |
| 117 | )?) | 117 | )?) |
| 118 | } | 118 | } |
| 119 | EncryptionMethod::Unsupported => return Err(ZipError::UnsupportedEncryptionMethod), | 119 | EncryptionMethod::Unsupported => { |
| 120 | return Err(ZipError::Unsupported("encryption method")) | ||
| 121 | } | ||
| 120 | }) | 122 | }) |
| 121 | } | 123 | } |
| 122 | } | 124 | } |
| @@ -141,7 +143,7 @@ impl<Io: Read + Seek> Seek for Encryption<Io> { | |||
| 141 | Self::None(io) => io.seek(pos), | 143 | Self::None(io) => io.seek(pos), |
| 142 | _ => Err(IoError::new( | 144 | _ => Err(IoError::new( |
| 143 | IoErrorKind::Unsupported, | 145 | IoErrorKind::Unsupported, |
| 144 | ZipError::EncryptedDataIsUnseekable, | 146 | ZipError::UnseekableFile, |
| 145 | )), | 147 | )), |
| 146 | } | 148 | } |
| 147 | } | 149 | } |
| @@ -182,8 +184,8 @@ impl<Io: Read + Seek> Compression<Io> { | |||
| 182 | } | 184 | } |
| 183 | CompressionMethod::Zstd => Self::Zstd(ZstdDecoder::new(io)?), | 185 | CompressionMethod::Zstd => Self::Zstd(ZstdDecoder::new(io)?), |
| 184 | CompressionMethod::Xz => Self::Xz(XzDecoder::new(io)), | 186 | CompressionMethod::Xz => Self::Xz(XzDecoder::new(io)), |
| 185 | CompressionMethod::Unsupported(id) => { | 187 | CompressionMethod::Unsupported => { |
| 186 | return Err(ZipError::UnsupportedCompressionMethod(id)) | 188 | return Err(ZipError::Unsupported("compression method")); |
| 187 | } | 189 | } |
| 188 | }) | 190 | }) |
| 189 | } | 191 | } |
| @@ -209,7 +211,7 @@ impl<Io: Read + Seek> Seek for Compression<Io> { | |||
| 209 | Compression::Store(io) => io.seek(pos), | 211 | Compression::Store(io) => io.seek(pos), |
| 210 | _ => Err(IoError::new( | 212 | _ => Err(IoError::new( |
| 211 | IoErrorKind::Unsupported, | 213 | IoErrorKind::Unsupported, |
| 212 | ZipError::CompressedDataIsUnseekable, | 214 | ZipError::UnseekableFile, |
| 213 | )), | 215 | )), |
| 214 | } | 216 | } |
| 215 | } | 217 | } |
| @@ -235,7 +237,7 @@ impl<'d, Io: Read + Seek> ZipFileReader<'d, Io> { | |||
| 235 | 237 | ||
| 236 | let buf = io.read_arr::<30>()?; | 238 | let buf = io.read_arr::<30>()?; |
| 237 | if buf[..4] != FILE_HEADER_SIGNATURE { | 239 | if buf[..4] != FILE_HEADER_SIGNATURE { |
| 238 | return Err(ZipError::InvalidFileHeaderSignature); | 240 | return Err(ZipError::InvalidSignature("FileHeader")); |
| 239 | } | 241 | } |
| 240 | 242 | ||
| 241 | let cursor = io.seek(SeekFrom::Start( | 243 | let cursor = io.seek(SeekFrom::Start( |
diff --git a/tests/zip.rs b/tests/zip.rs index e44098c..e2b5c20 100644 --- a/tests/zip.rs +++ b/tests/zip.rs | |||
| @@ -164,5 +164,5 @@ fn test_zip() { | |||
| 164 | #[test] | 164 | #[test] |
| 165 | fn test_bad_zip() { | 165 | fn test_bad_zip() { |
| 166 | assert!(Archive::<Zip>::read_from_file("tests/files/blank") | 166 | assert!(Archive::<Zip>::read_from_file("tests/files/blank") |
| 167 | .is_err_and(|e| e == ZipError::EocdrNotFound)); | 167 | .is_err_and(|e| e == ZipError::StructNotFound("Eocdr"))); |
| 168 | } | 168 | } |
