Expand description
The brotli family (brotli, unbrotli, brcat): stuffr behaving as the
brotli 1.2.1 command line tool.
A port of c/tools/brotli.c of the 1.2.1 tag (MIT; LICENSE-brotli)
over the doc-hidden stuffr::brotli_opts seam. cli.rs is
ParseParams, messages.rs holds every string byte for byte. The
reference reads no environment variable and installs no signal handler.
Streams (probed, ruling T1-a): -h writes the help text to standard
error and exits 0; a usage error writes its message (if any) to standard
error, the help text to standard output and exits 1; -V writes
brotli 1.2.1 to standard output. Exit codes are 0 and 1 only.
The promise. Stdout, stderr and exit codes (0 and 1) are those of
brotli 1.2.1 on both build tiers, and the .br bytes are identical on
the C tier (brotli-c, libbrotli 1.2.1 vendored; also in c-backed).
-V prints brotli 1.2.1; there is no stuffr banner.
Known deviations (the source of truth; the README mirrors it with the same numbers and words):
- Pure tier: the
.brbytes are compatible, not identical. brotli 1.2.1 decodes them to the input; the C tier’s are the reference’s. - Pure tier:
-Dis refused in both directions (-D is not supported by this build (pure tier); build with --features brotli-c, exit 1, once the dictionary file has been read), and so is a one-byte-Ccomment when compressing (failed to emit metadata [NAME], exit 1; the pure encoder writes a corrupt stream for it). Every other-Clength, and--large_window, work. - Pure tier: a corrupt stream’s
reason:line can differ. The decoder cannot tell-10(BLOCK_LENGTH_2) from-9(BLOCK_LENGTH_1) and reports-9, and it accepts some streams libbrotli rejects with-9.-15is reported as-14where the decoder is at a metablock header. - An input that is also the output is refused, where the reference
truncates it, and with
-ddeletes it:brotli -f -o a a, a hard link or a symlink to the input as the output. stuffr printsinput file [NAME] is the same as the output fileand exits 1 before opening the output. - A later input operand that an earlier output would overwrite is
refused before the output is opened (
brotli -f a a.br,-df a.br a;input file [NAME] would be overwritten by the output of [NAME], exit 1), where the reference overwrites that input before reading it. -jremoves the source only after the output closed without error; the reference removes it even whenfclosefailed (ENOSPC, EIO), leaving a truncated output and no input. stuffr buffers its output in 64 KiB, the reference in stdio’s buffer, so on a full disk the failure may be reported asfclose failed [x]where the reference saysfailed to write output [x]. The output is removed either way.brotli - -(standard input named twice) writes both streams; the reference closes standard output after the first file and crashes on the second.could not read dictionary: out of memoryis never printed. The dictionary buffer (at mostMAX_DICTIONARY_SIZE, 50331660 bytes, about 48 MiB, the reference’s own limit) is a plain allocation; when the allocator cannot give it, Rust aborts the process (SIGABRT, status 134) where the reference prints that line and exits 1.- No signal handler, as the reference: an interrupt leaves the partial output where it was written (outputs are created directly under their names, never through a temporary).
- A closed pipe kills stuffr by SIGPIPE, as it kills brotli under the
default disposition. Where the parent ignores SIGPIPE brotli answers
failed to write output [NAME]: Broken pipeand exits 1; stuffr still dies of the signal, because the Rust runtime ignores SIGPIPE beforemainand the inherited setting cannot be told apart. A permanent deviation, as in every family. - Hardening (ruling T5 of the 2026-10-31 security audit):
-fnever writes through a symlink at the output name. The reference opens a forced outputO_CREAT | O_TRUNCwithoutO_EXCL, so a symlink there, dangling or not, is followed and the file it names is created or truncated. stuffr unlinks the link and creates a fresh file (O_NOFOLLOW), its target untouched; without-fboth refuse it (O_EXCL), as before. The attributesCopyStatcopies are set after the checked close, as the reference sets them, but by name it follows a symlink there; stuffr reopens the outputO_NOFOLLOW, checks it is the file this run opened (device and inode) and sets times, mode and owner through that descriptor: if the name was swapped meanwhile they are not copied. Why: a planted link must not redirect a write or achmod.
files.rs is the file handling (NextFile, OpenFiles, CloseFiles,
CopyStat, ReadDictionary), codec.rs compression and the
decompression loop, decoding (with -t, -K and the comment check).
Functions§
- run
- Entry point for the three names;
nameis the canonical invoked name,argv0the program as invoked (its last component is the name the help text prints) andargsthe arguments after it.