diff --git a/Cargo.lock b/Cargo.lock index 709f0d8..b9708ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -119,15 +119,16 @@ dependencies = [ ] [[package]] -name = "async-compression" -version = "0.4.42" +name = "async-deflate-zip" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" +checksum = "613debb46d5477cd9ac7ab57e6ae1c6846383daa199dba9fe3153fc31be3ae86" dependencies = [ - "compression-codecs", - "compression-core", - "futures-io", + "crc32fast", + "flate2", "pin-project-lite", + "time", + "tokio", ] [[package]] @@ -152,22 +153,6 @@ dependencies = [ "syn", ] -[[package]] -name = "async_zip" -version = "0.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c50d65ce1b0e0cb65a785ff615f78860d7754290647d3b983208daa4f85e6" -dependencies = [ - "async-compression", - "chrono", - "crc32fast", - "futures-lite", - "pin-project", - "thiserror", - "tokio", - "tokio-util", -] - [[package]] name = "atomic-waker" version = "1.1.2" @@ -261,15 +246,6 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" -[[package]] -name = "bzip2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" -dependencies = [ - "libbz2-rs-sys", -] - [[package]] name = "cc" version = "1.2.61" @@ -395,24 +371,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "compression-codecs" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce2548391e9c1929c21bf6aa2680af86fe4c1b33e6cea9ac1cfeec0bd11218cf" -dependencies = [ - "bzip2", - "compression-core", - "flate2", - "liblzma", -] - -[[package]] -name = "compression-core" -version = "0.4.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" - [[package]] name = "const-oid" version = "0.9.6" @@ -567,6 +525,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + [[package]] name = "difflib" version = "0.4.0" @@ -632,8 +599,8 @@ dependencies = [ "anyhow", "assert_cmd", "assert_fs", + "async-deflate-zip", "async-stream", - "async_zip", "base64", "bytes", "chardetng", @@ -654,7 +621,6 @@ dependencies = [ "if-addrs", "indexmap", "lazy_static", - "liblzma", "log", "md5", "mime_guess", @@ -824,19 +790,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - [[package]] name = "futures-macro" version = "0.3.32" @@ -1419,38 +1372,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" -[[package]] -name = "libbz2-rs-sys" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a6a8c165077efc8f3a971534c50ea6a1a18b329ef4a66e897a7e3a1494565f" - [[package]] name = "libc" version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" -[[package]] -name = "liblzma" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6033b77c21d1f56deeae8014eb9fbe7bdf1765185a6c508b5ca82eeaed7f899" -dependencies = [ - "liblzma-sys", -] - -[[package]] -name = "liblzma-sys" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a60851d15cd8c5346eca4ab8babff585be2ae4bc8097c067291d3ffe2add3b6" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -1549,6 +1476,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + [[package]] name = "num-traits" version = "0.2.19" @@ -1558,6 +1491,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -1576,12 +1518,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - [[package]] name = "password-hash" version = "0.6.1" @@ -1594,26 +1530,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "pin-project" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf0d9e68100b3a7989b4901972f265cd542e560a3a8a724e1e20322f4d06ce9" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a990e22f43e84855daf260dded30524ef4a9021cc7541c26540500a50b624389" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.17" @@ -1630,12 +1546,6 @@ dependencies = [ "spki", ] -[[package]] -name = "pkg-config" -version = "0.3.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" - [[package]] name = "port_check" version = "0.3.0" @@ -1651,6 +1561,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -2440,6 +2356,27 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde_core", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + [[package]] name = "tinystr" version = "0.8.3" diff --git a/Cargo.toml b/Cargo.toml index 4b46e35..b912a03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,7 @@ percent-encoding = "2.3" serde = { version = "1", features = ["derive"] } serde_json = "1" futures-util = { version = "0.3", default-features = false, features = ["alloc"] } -async_zip = { version = "0.0.18", default-features = false, features = ["deflate", "bzip2", "xz", "chrono", "tokio"] } -liblzma = { version = "0.4", features = ["static"] } # avoid dynamic linking issues on MacOS +async-deflate-zip = "0.1.1" headers = "0.4" mime_guess = "2.0" if-addrs = "0.15" diff --git a/src/args.rs b/src/args.rs index 306fa6e..aa43b6c 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,5 +1,5 @@ use anyhow::{bail, Context, Result}; -use async_zip::Compression; +use async_deflate_zip::Compression; use clap::builder::{PossibleValue, PossibleValuesParser}; use clap::{value_parser, Arg, ArgAction, ArgMatches, Command, ValueEnum}; use clap_complete::{generate, Generator, Shell}; @@ -540,10 +540,10 @@ impl ValueEnum for Compress { impl Compress { pub fn to_compression(self) -> Compression { match self { - Compress::None => Compression::Stored, - Compress::Low => Compression::Deflate, - Compress::Medium => Compression::Bz, - Compress::High => Compression::Xz, + Compress::None => Compression::none(), + Compress::Low => Compression::fast(), + Compress::Medium => Compression::default(), + Compress::High => Compression::best(), } } } diff --git a/src/server.rs b/src/server.rs index b61224e..24eab59 100644 --- a/src/server.rs +++ b/src/server.rs @@ -3,14 +3,11 @@ use crate::auth::{www_authenticate, AccessPaths, AccessPerm}; use crate::http_utils::{body_full, IncomingStream, LengthLimitedStream}; use crate::noscript::{detect_noscript, generate_noscript_html}; -use crate::utils::{ - decode_uri, encode_uri, get_file_mtime_and_mode, get_file_name, glob, parse_range, - try_get_file_name, -}; +use crate::utils::{decode_uri, encode_uri, get_file_name, glob, parse_range, try_get_file_name}; use crate::Args; use anyhow::{anyhow, Result}; -use async_zip::{tokio::write::ZipFileWriter, Compression, ZipDateTime, ZipEntryBuilder}; +use async_deflate_zip::{Compression, ZipWriter}; use base64::{engine::general_purpose::STANDARD, Engine as _}; use bytes::Bytes; use chrono::{LocalResult, TimeZone, Utc}; @@ -46,7 +43,6 @@ use tokio::fs::File; use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWrite}; use tokio::{fs, io}; -use tokio_util::compat::FuturesAsyncWriteCompatExt; use tokio_util::io::{ReaderStream, StreamReader}; use uuid::Uuid; use walkdir::{DirEntry, WalkDir}; @@ -1762,7 +1758,6 @@ async fn zip_dir( serve_path: PathBuf, running: Arc, ) -> Result<()> { - let mut writer = ZipFileWriter::with_tokio(writer); let hidden = Arc::new(hidden.to_vec()); let zip_paths = tokio::task::spawn(collect_dir_entries( access_paths, @@ -1774,6 +1769,7 @@ async fn zip_dir( move |x| x.path().symlink_metadata().is_ok() && x.file_type().is_file(), )) .await?; + let mut zip = ZipWriter::new(&mut *writer).with_level(compression); for zip_path in zip_paths.into_iter() { let filename = match zip_path .strip_prefix(dir) @@ -1784,16 +1780,21 @@ async fn zip_dir( Some(v) => v, None => continue, }; - let (datetime, mode) = get_file_mtime_and_mode(&zip_path).await?; - let builder = ZipEntryBuilder::new(filename.into(), compression) - .unix_permissions(mode) - .last_modification_date(ZipDateTime::from_chrono(&datetime)); let mut file = File::open(&zip_path).await?; - let mut file_writer = writer.write_entry_stream(builder).await?.compat_write(); - io::copy(&mut file, &mut file_writer).await?; - file_writer.into_inner().close().await?; + let meta = file.metadata().await?; + let mut entry = zip.append_file(&filename).await?; + if let Ok(mtime) = meta.modified() { + entry.set_mtime(mtime); + } + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + entry.set_permissions(meta.permissions().mode() & 0o777); + } + io::copy(&mut file, &mut entry).await?; + entry.close().await?; } - writer.close().await?; + zip.finalize().await?; Ok(()) } diff --git a/src/utils.rs b/src/utils.rs index c22e494..49b087e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Context, Result}; -use chrono::{DateTime, Utc}; + #[cfg(feature = "tls")] use rustls_pki_types::{pem::PemObject, CertificateDer, PrivateKeyDer}; use std::{ @@ -31,21 +31,6 @@ pub fn get_file_name(path: &Path) -> &str { .unwrap_or_default() } -#[cfg(unix)] -pub async fn get_file_mtime_and_mode(path: &Path) -> Result<(DateTime, u16)> { - use std::os::unix::prelude::MetadataExt; - let meta = tokio::fs::metadata(path).await?; - let datetime: DateTime = meta.modified()?.into(); - Ok((datetime, meta.mode() as u16)) -} - -#[cfg(not(unix))] -pub async fn get_file_mtime_and_mode(path: &Path) -> Result<(DateTime, u16)> { - let meta = tokio::fs::metadata(&path).await?; - let datetime: DateTime = meta.modified()?.into(); - Ok((datetime, 0o644)) -} - pub fn try_get_file_name(path: &Path) -> Result<&str> { path.file_name() .and_then(|v| v.to_str())