diff --git a/README.md b/README.md index 85c34f11..93e71ef5 100644 --- a/README.md +++ b/README.md @@ -731,6 +731,7 @@ select which type of archive you want in the `[⚙️] config` tab: * `up2k.db` and `dir.txt` is always excluded * bsdtar supports streaming unzipping: `curl foo?zip | bsdtar -xv` * good, because copyparty's zip is faster than tar on small files + * but `?tar` is better for large files, especially if the total exceeds 4 GiB * `zip_crc` will take longer to download since the server has to read each file twice * this is only to support MS-DOS PKZIP v2.04g (october 1993) and older * how are you accessing copyparty actually diff --git a/copyparty/szip.py b/copyparty/szip.py index 8e0ffee2..91fa2a34 100644 --- a/copyparty/szip.py +++ b/copyparty/szip.py @@ -54,6 +54,7 @@ def gen_fdesc(sz: int, crc32: int, z64: bool) -> bytes: def gen_hdr( h_pos: Optional[int], + z64: bool, fn: str, sz: int, lastmod: int, @@ -70,7 +71,6 @@ def gen_hdr( # appnote 4.5 / zip 3.0 (2008) / unzip 6.0 (2009) says to add z64 # extinfo for values which exceed H, but that becomes an off-by-one # (can't tell if it was clamped or exactly maxval), make it obvious - z64 = sz >= 0xFFFFFFFF z64v = [sz, sz] if z64 else [] if h_pos and h_pos >= 0xFFFFFFFF: # central, also consider ptr to original header @@ -244,6 +244,7 @@ class StreamZip(StreamArc): sz = st.st_size ts = st.st_mtime + h_pos = self.pos crc = 0 if self.pre_crc: @@ -252,8 +253,12 @@ class StreamZip(StreamArc): crc &= 0xFFFFFFFF - h_pos = self.pos - buf = gen_hdr(None, name, sz, ts, self.utf8, crc, self.pre_crc) + # some unzip-programs expect a 64bit data-descriptor + # even if the only 32bit-exceeding value is the offset, + # so force that by placeholdering the filesize too + z64 = h_pos >= 0xFFFFFFFF or sz >= 0xFFFFFFFF + + buf = gen_hdr(None, z64, name, sz, ts, self.utf8, crc, self.pre_crc) yield self._ct(buf) for buf in yieldfile(src, self.args.iobuf): @@ -266,8 +271,6 @@ class StreamZip(StreamArc): self.items.append((name, sz, ts, crc, h_pos)) - z64 = sz >= 4 * 1024 * 1024 * 1024 - if z64 or not self.pre_crc: buf = gen_fdesc(sz, crc, z64) yield self._ct(buf) @@ -306,7 +309,8 @@ class StreamZip(StreamArc): cdir_pos = self.pos for name, sz, ts, crc, h_pos in self.items: - buf = gen_hdr(h_pos, name, sz, ts, self.utf8, crc, self.pre_crc) + z64 = h_pos >= 0xFFFFFFFF or sz >= 0xFFFFFFFF + buf = gen_hdr(h_pos, z64, name, sz, ts, self.utf8, crc, self.pre_crc) mbuf += self._ct(buf) if len(mbuf) >= 16384: yield mbuf