Skip to main content

Module bzip2recover

Module bzip2recover 

Source
Expand description

bzip2recover: stuffr behaving as bzip2recover 1.0.8.

Ported from bzip2 1.0.8’s bzip2recover.c, copyright (C) 1996-2019 Julian Seward, under the bzip2 licence reproduced in LICENSE-bzip2. main is followed line by line, quirks included:

  • two passes over the input: the first finds every 48-bit block and end-of-stream magic and records the blocks between them; the second copies each recorded block’s bits into its own stream;
  • a “block” is whatever lies between two magics and is recorded when it spans at least 130 bits, measured in unsigned 64-bit arithmetic, so a magic that follows another within 49 bits wraps round and is recorded with its end before its start (the second pass then writes nothing for it);
  • a block the input ends inside is reported as (incomplete) but never written;
  • each output is BZh9, the block magic, the block’s bits, the end-of-stream magic and, as the combined CRC, the block’s own stored CRC: nothing is decompressed, recompressed or checked;
  • outputs are rec%05d and the input’s base name, split at the last /, with .bz2 appended unless the result already ends in it, opened as fopen(.., "wb") does (created mode 0666 less the umask, or an existing file truncated). So, as upstream does, an output is written through a symlink already at its name and truncates a file already there; Debian’s bzip2recover-race-open-output.diff refuses both;
  • the limits: BZ_MAX_FILENAME (an operand of 1980 bytes or more is refused) and BZ_MAX_HANDLED_BLOCKS (50000), with their messages; every failure exits 1.

Memory is bounded by the block cap: the input is streamed twice, and only the recorded blocks’ bit positions (at most 50000 pairs) are kept.

Known deviations from bzip2recover 1.0.8:

  • At exactly 50000 magics (for example 49999 blocks plus the end-of-stream marker) with at least 40 bits after the last, 1.0.8 writes past its bEnd array and, on macOS, silently drops block 1; stuffr writes it, as if the arrays were 50001 long. Debian’s gcc build of the same source instead stops at the 50000th magic (“more than 50000 blocks”, exit 1); stuffr, like upstream, stops at the 50001st.
  • Like bzip2, a read error is reported with its strerror text; a stale errno that the C library left nonzero at a clean end of file (which would make 1.0.8 report a read error) is not reproduced.
  • mallocFail cannot happen: nothing is allocated per bit or per block beyond the bounded position list.

Functions§

run
Entry point: argv0 is the program path as invoked (bzip2recover prints it in full), args the arguments after it.