Skip to content

Commit 87aa047

Browse files
committed
Add support for zip v8
1 parent bce9439 commit 87aa047

5 files changed

Lines changed: 129 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2020
- Browser process no longer inherits stdout
2121
- Update reqwest to 0.13
2222
- Update thiserror to 2
23+
- Add support for zip8 and make it default
2324

2425
### Added
2526

chromiumoxide_fetcher/Cargo.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,20 @@ anyhow = "1"
3131
directories = "6"
3232
serde = { version = "1", features = ["derive"] }
3333
tracing = "0.1"
34-
zip = { version = "0.6", default-features = false, features = ["deflate"] }
34+
zip-0_2 = { package = "zip", version = "0.6", default-features = false, features = [
35+
"deflate",
36+
], optional = true }
37+
zip-8 = { package = "zip", version = "8", default-features = false, features = [
38+
"deflate-flate2-zlib-rs",
39+
], optional = true }
3540
tokio = { version = "1", features = ["fs", "io-util"] }
3641
reqwest = { version = "0.13", default-features = false, features = ["json"] }
3742

3843
[target.'cfg(target_os = "windows")'.dependencies]
3944
windows-version = "0.1"
4045

4146
[features]
42-
default = ["rustls"]
47+
default = ["rustls", "zip-8"]
4348

4449
rustls = ["reqwest/rustls"]
4550
native-tls = ["reqwest/native-tls"]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#[cfg(feature = "zip-0_2")]
2+
mod zip_0_2;
3+
#[cfg(feature = "zip-0_2")]
4+
pub use zip_0_2::ZipArchive;
5+
6+
#[cfg(feature = "zip-8")]
7+
mod zip_8;
8+
#[cfg(feature = "zip-8")]
9+
pub use zip_8::ZipArchive;

chromiumoxide_fetcher/src/runtime/zip.rs renamed to chromiumoxide_fetcher/src/runtime/zip/zip_0_6.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ fn create_symlink(link_target: Vec<u8>, link_path: &Path) -> ZipResult<()> {
102102
fn create_symlink(link_target: Vec<u8>, link_path: &Path) -> ZipResult<()> {
103103
// Only supports UTF-8 paths which is enough for our usecase
104104
let link_target = String::from_utf8(link_target)
105-
.map_err(|_| ZipError::InvalidArchive("Invalid synmlink target name"))?;
105+
.map_err(|_| ZipError::InvalidArchive("Invalid symlink target name"))?;
106106
std::os::windows::fs::symlink_file(link_target, link_path)?;
107107

108108
Ok(())
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use std::fs;
2+
use std::io::{self, Read, Seek};
3+
use std::ops::{Deref, DerefMut};
4+
use std::path::Path;
5+
6+
use zip_8::{
7+
read::ZipFile,
8+
result::{ZipError, ZipResult},
9+
};
10+
11+
#[derive(Clone, Debug)]
12+
pub struct ZipArchive<R: Read + Seek>(zip_8::ZipArchive<R>);
13+
14+
impl<R: Read + Seek> Deref for ZipArchive<R> {
15+
type Target = zip_8::ZipArchive<R>;
16+
17+
fn deref(&self) -> &Self::Target {
18+
&self.0
19+
}
20+
}
21+
22+
impl<R: Read + Seek> DerefMut for ZipArchive<R> {
23+
fn deref_mut(&mut self) -> &mut Self::Target {
24+
&mut self.0
25+
}
26+
}
27+
28+
impl<R: Read + Seek> ZipArchive<R> {
29+
pub fn new(reader: R) -> ZipResult<Self> {
30+
zip_8::ZipArchive::new(reader).map(Self)
31+
}
32+
33+
/// We need this custom extract function to support symlinks.
34+
/// This is based on https://github.com/zip-rs/zip/pull/213.
35+
///
36+
/// We must be careful with this implementation since it is not
37+
/// protected against malicious symlinks, but we trust the binaries
38+
/// provided by chromium.
39+
pub fn extract<P: AsRef<Path>>(&mut self, directory: P) -> ZipResult<()> {
40+
for i in 0..self.len() {
41+
let mut file = self.by_index(i)?;
42+
43+
let filepath = file
44+
.enclosed_name()
45+
.ok_or(ZipError::InvalidArchive("Invalid file path".into()))?;
46+
let outpath = directory.as_ref().join(filepath);
47+
48+
if file.is_dir() {
49+
fs::create_dir_all(&outpath)?;
50+
} else {
51+
if let Some(p) = outpath.parent() {
52+
if !p.exists() {
53+
fs::create_dir_all(p)?;
54+
}
55+
}
56+
57+
match read_symlink(&mut file)? {
58+
Some(target) => {
59+
create_symlink(target, &outpath)?;
60+
}
61+
None => {
62+
let mut outfile = fs::File::create(&outpath)?;
63+
io::copy(&mut file, &mut outfile)?;
64+
65+
// Get and Set permissions
66+
#[cfg(unix)]
67+
{
68+
use std::os::unix::fs::PermissionsExt;
69+
if let Some(mode) = file.unix_mode() {
70+
fs::set_permissions(&outpath, fs::Permissions::from_mode(mode))?;
71+
}
72+
}
73+
}
74+
}
75+
}
76+
}
77+
Ok(())
78+
}
79+
}
80+
81+
fn read_symlink<R: Read + Seek>(entry: &mut ZipFile<'_, R>) -> ZipResult<Option<Vec<u8>>> {
82+
if let Some(mode) = entry.unix_mode() {
83+
const S_IFLNK: u32 = 0o120000; // symbolic link
84+
if mode & S_IFLNK == S_IFLNK {
85+
let mut contents = Vec::new();
86+
entry.read_to_end(&mut contents)?;
87+
return Ok(Some(contents));
88+
}
89+
}
90+
Ok(None)
91+
}
92+
93+
#[cfg(target_family = "unix")]
94+
fn create_symlink(link_target: Vec<u8>, link_path: &Path) -> ZipResult<()> {
95+
use std::os::unix::ffi::OsStringExt as _;
96+
97+
let link_target = std::ffi::OsString::from_vec(link_target);
98+
std::os::unix::fs::symlink(link_target, link_path)?;
99+
100+
Ok(())
101+
}
102+
103+
#[cfg(target_family = "windows")]
104+
fn create_symlink(link_target: Vec<u8>, link_path: &Path) -> ZipResult<()> {
105+
// Only supports UTF-8 paths which is enough for our usecase
106+
let link_target = String::from_utf8(link_target)
107+
.map_err(|_| ZipError::InvalidArchive("Invalid symlink target name".into()))?;
108+
std::os::windows::fs::symlink_file(link_target, link_path)?;
109+
110+
Ok(())
111+
}

0 commit comments

Comments
 (0)