Expand description
The unzip family (unzip, zipinfo, funzip): stuffr behaving as the
platform’s Info-ZIP UnZip 6.00.
A port of Apple’s zip-33 tree (unzip/unzip60/, the Info-ZIP
licence version 2009-Jan-02, LICENSE-infozip; this is an altered
version, marked as such by every banner). Each ported function carries
// port: <file>.c:<function>, each Apple change // apple: <file>.c:<line>, each Ubuntu difference // ubuntu: <patch> or // ubuntu: -D<DEFINE>, and each rule taken from the binary rather than the
source // probe: <command>; where the two disagree, the binary wins.
Every string is in messages.rs.
Flavours (Flavour, flavour.rs): Apple’s /usr/bin/unzip on
macOS and the BSDs, Ubuntu 24.04’s 6.0-28ubuntu4.1 elsewhere
(default_flavour), or as STUFFR_UNZIP_FLAVOR (apple, ubuntu)
says; run reads it once, and anything else in it is refused, exit 1,
in stuffr’s own words. Ubuntu’s build options (its -D DEFINES) and
its patch series are flavour checks at the points they change
behaviour (R13), each marked // ubuntu:.
G becomes Uz (R5): Info-ZIP’s global G (and its uO
options) is one value per run, holding the host, the flavour, the
options and the state, so a sandboxed run ([run_in_counted]) touches
nothing of the process.
What is here: the names, the flavour, the
command line (unzip.c’s unzip() front half and uz_opts(),
zipinfo.c’s zi_opts(), envargs.c), the usage screens, -hh, the
-v screen and funzip’s usage (Task 7); opening archives, wildcard
archive names, the end records, Zip64, the central directory walk,
wildcards and unzip’s listings -l, -v, -z, -T (process.rs,
unix/mod.rs, matching.rs, list.rs, fileio.rs: Task 8); zipinfo’s
listings, every format, the totals and the -v report (zipinfo/:
Task 9); testing and extraction (extract/: extract.c, fileio.c’s
output side, crypt.c’s decrypt(); unix/mapname.rs, unix/attrs.rs:
unix.c’s names, paths, modes, times and symlinks; unix/beneath.rs:
the resolve-beneath walk every change goes through; Task 10); the
terminal (ttyio.rs: getp() on /dev/tty, zgetch(),
screensize(); fileio.rs: UzpPassword(), UzpMorePause(); -M’s
line counting in Uz::print_raw; crypt.c’s retries; the interrupt
handler, exit 80: Task 11); funzip (funzip.rs: funzip.c, Task 12);
Ubuntu’s build options and patch series as flavour checks throughout
(Tasks 13 and 14; process/unicode.rs is Ubuntu’s alone).
Known deviations (the source of truth; the README and the spec mirror
this list):
- SIGPIPE:
runrestores SIGPIPE’s default action, as the other families do; under a parent that ignores SIGPIPE, unzip seesEPIPEand stuffr still dies of the signal (the Rust runtime ignores it beforemain, so the inherited disposition cannot be told apart). - The first banner line of each program’s usage and
-vnames stuffr and says it is altered (Info-ZIP licence clause 3):UnZip 6.00 of 20 April 2009, by stuffr X.Y.Z (altered; original by Info-ZIP, with modifications by Apple Inc.).(Ubuntu:(altered; Debian's build, original by Info-ZIP).), and likewise for zipinfo and funzip. That line is wider than the pager’s 80 columns, so under-Mit counts as two screen lines and-Mhpauses one text line earlier than the reference (P26).-v’sCompiled withline is the recorded reference build’s (Apple: this release’s macOS build), so other macOS builds print a different one. - Pre-existing symlinks: the Ubuntu flavour also stays beneath the
extraction root, as Apple’s does. On unix only: off unix (Windows)
the walk (
unix/beneath.rs’simp_std) follows symlinks, so neither flavour is contained there. - The archive being read is never overwritten.
-O/-I(Ubuntu) convert names throughiconv(3); they are unavailable on Windows, where they are parsed as Ubuntu parses them and convert nothing, as a conversion Ubuntu’siconv_open()refuses (silently: the names stay as stored; ruling T14-5).- Locale-dependent output is identical under
C,C.UTF-8anden_US.UTF-8only. - On macOS the Ubuntu flavour also propagates the archive’s quarantine attribute (R9), as Apple’s does.
- The terminal (T11-1, P28): after a prompt, a pager key or an
interrupt, the terminal’s mode is put back exactly as it was, where
unzip’s
echon()only sets echo again (after an interrupt in the-Mpager it leaves canonical mode off). A SIGABRT stuffr raises itself (a crash) kills it by the signal; one sent by another process exits 80, as unzip does for both. funzip installs no handler, so a signal at its password prompt kills it, echo off; stuffr puts the mode back first, then dies of the same signal (host::arm_tty_restore). - funzip never loses a write failure (T12-4): a failed write to
standard output is answered
out of space on stdout, exit 9, on a real host too. The C writes through buffered stdio and does not check its finalfflush(), so it loses the data and exits 0. - Undefined behaviour and endless loops are not reproduced. Where a
reference’s behaviour is undefined, or never ends, stuffr gives a
defined answer instead. Ubuntu’s bzip2 decoding loops for ever on a
truncated entry; stuffr answers as for bad bzip2 data, exit 2
(T13-2). Apple’s
-:on a../directory entry changes the directory above the extraction root; stuffr refuses (T10-10). After a failed create Apple writes through the previous entry’s closed stream; stuffr says “cannot create” and goes on (T10-11). At the end of input the C asks for a new name for ever at the rename prompt, and waits for ever at the-Mpager’s; stuffr takes[N]oneand stops pausing (T10-9, T11-4). Buffer overflows are answered in both flavours with the forms of Ubuntu’s CVE fixes: a method above 999 isUnkand four hex digits (Unk03E8), and a password prompt whose names are too long is “Enter password: “ (T11-5). The full set is in the code’s// ruling:comments.
Enums§
- Flavour
- Which reference the family behaves as.
Functions§
- default_
flavour - The flavour a build uses when
STUFFR_UNZIP_FLAVORis unset or empty: Apple on macOS and the BSDs, Ubuntu everywhere else, Windows included. - run
- Entry point for
unzip,zipinfoandfunzip;nameis the canonical invoked name,argv0the program as invoked (unzip.c reads its last component for ZipInfo mode) andargsthe arguments after it.