diff options
Diffstat (limited to 'src/zip/driver.rs')
| -rw-r--r-- | src/zip/driver.rs | 70 |
1 files changed, 37 insertions, 33 deletions
diff --git a/src/zip/driver.rs b/src/zip/driver.rs index 7758479..0502c85 100644 --- a/src/zip/driver.rs +++ b/src/zip/driver.rs | |||
| @@ -79,7 +79,7 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 79 | // Search eocdr | 79 | // Search eocdr |
| 80 | let limit = 65557.min(io.seek(SeekFrom::End(0))?) as i64; | 80 | let limit = 65557.min(io.seek(SeekFrom::End(0))?) as i64; |
| 81 | let start = io.seek(SeekFrom::End(-limit))?; | 81 | let start = io.seek(SeekFrom::End(-limit))?; |
| 82 | let pos = start | 82 | let eocdr_pos = start |
| 83 | + io.read_vec( | 83 | + io.read_vec( |
| 84 | (limit as usize) | 84 | (limit as usize) |
| 85 | .checked_sub(18) | 85 | .checked_sub(18) |
| @@ -90,46 +90,50 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> { | |||
| 90 | .ok_or(ZipError::StructNotFound("Eocdr"))? 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(eocdr_pos + 4))?; |
| 94 | let buf = io.read_arr::<18>()?; | 94 | let buf = io.read_arr::<18>()?; |
| 95 | let eocdr: Eocdr = deserialize(&buf).unwrap(); | 95 | let eocdr: Eocdr = deserialize(&buf).unwrap(); |
| 96 | let comment = String::from_cp437(io.read_vec(eocdr.comment_len as usize)?); | 96 | let comment = String::from_cp437(io.read_vec(eocdr.comment_len as usize)?); |
| 97 | 97 | ||
| 98 | let mut cd_pointer = eocdr.cd_pointer as u64; | ||
| 99 | let mut cd_size = eocdr.cd_size as u64; | ||
| 100 | let mut cd_records = eocdr.cd_records as u64; | ||
| 101 | |||
| 98 | // Try to find eocdr64locator | 102 | // Try to find eocdr64locator |
| 99 | io.seek(SeekFrom::Start(pos.saturating_sub(20)))?; | 103 | if eocdr_pos >= 20 { |
| 100 | let buf = io.read_arr::<20>()?; | 104 | io.seek(SeekFrom::Start(eocdr_pos - 20))?; |
| 101 | let (cd_pointer, cd_size, cd_records) = if buf[..4] == EOCDR64_LOCATOR_SIGNATURE { | 105 | let buf = io.read_arr::<20>()?; |
| 102 | // Locator found | ||
| 103 | let eocdr64locator: Eocdr64Locator = deserialize(&buf[4..]).unwrap(); | ||
| 104 | |||
| 105 | io.seek(SeekFrom::Start(eocdr64locator.eocdr64_pointer))?; | ||
| 106 | if io.read_arr()? != EOCDR64_SIGNATURE { | ||
| 107 | return Err(ZipError::InvalidSignature("Eocdr64")); | ||
| 108 | } | ||
| 109 | 106 | ||
| 110 | let eocdr64: Eocdr64 = deserialize(&io.read_arr::<52>()?).unwrap(); | 107 | if buf[..4] == EOCDR64_LOCATOR_SIGNATURE { |
| 111 | if eocdr64.cd_pointer + eocdr64.cd_size > eocdr64locator.eocdr64_pointer { | 108 | let locator: Eocdr64Locator = deserialize(&buf[4..]).unwrap(); |
| 112 | return Err(ZipError::Overlapping( | 109 | io.seek(SeekFrom::Start(locator.eocdr64_pointer))?; |
| 113 | "Central directory records", | ||
| 114 | "Zip64 end of central directory record", | ||
| 115 | )); | ||
| 116 | } | ||
| 117 | 110 | ||
| 118 | (eocdr64.cd_pointer, eocdr64.cd_size, eocdr64.cd_records) | 111 | if io.read_arr()? != EOCDR64_SIGNATURE { |
| 119 | } else { | 112 | return Err(ZipError::InvalidSignature("Eocdr64")); |
| 120 | if (eocdr.cd_pointer + eocdr.cd_size) as u64 > pos { | 113 | } |
| 121 | return Err(ZipError::Overlapping( | 114 | |
| 122 | "Central directory records", | 115 | if locator.eocdr64_pointer + 76 > eocdr_pos { |
| 123 | "End of central directory record", | 116 | return Err(ZipError::Overlapping("Eocdr64", "Eocdr64Locator")); |
| 124 | )); | 117 | } |
| 125 | } | ||
| 126 | 118 | ||
| 127 | ( | 119 | let eocdr64: Eocdr64 = deserialize(&io.read_arr::<54>()?).unwrap(); |
| 128 | eocdr.cd_pointer as u64, | 120 | if locator.eocdr64_pointer + eocdr64.eocdr64_size + 32 > eocdr_pos { |
| 129 | eocdr.cd_size as u64, | 121 | return Err(ZipError::Overlapping("Eocdr64", "Eocdr64Locator")); |
| 130 | eocdr.cd_records as u64, | 122 | } |
| 131 | ) | 123 | |
| 132 | }; | 124 | cd_pointer = eocdr64.cd_pointer; |
| 125 | cd_size = eocdr64.cd_size; | ||
| 126 | cd_records = eocdr64.cd_records; | ||
| 127 | |||
| 128 | if cd_pointer + cd_size > locator.eocdr64_pointer { | ||
| 129 | return Err(ZipError::Overlapping("Cdr", "Eocdr64")); | ||
| 130 | } | ||
| 131 | } else if cd_pointer + cd_size > eocdr_pos { | ||
| 132 | return Err(ZipError::Overlapping("Cdr", "Eocdr")); | ||
| 133 | } | ||
| 134 | } else if cd_pointer + cd_size > eocdr_pos { | ||
| 135 | return Err(ZipError::Overlapping("Cdr", "Eocdr")); | ||
| 136 | } | ||
| 133 | 137 | ||
| 134 | // Read cd records | 138 | // Read cd records |
| 135 | let mut indexes = Map::with_capacity(cd_records as usize); | 139 | let mut indexes = Map::with_capacity(cd_records as usize); |
