3.8.8 ("make ARCHIVE_FATAL sticky in data-reading entry points",
commit e1f890dc) made archive_seek_data() set
a->archive.state = ARCHIVE_STATE_FATAL whenever the call returned
ARCHIVE_FATAL. That is correct for genuine I/O / parse failures
returned by a format's seek_data() implementation, but it also
poisoned the archive in two cases where seeking is simply
unsupported for the current format:
1. The seek_data == NULL branch in archive_seek_data() itself
(no format_seek_data_block registered: ustar/tar, the
streaming ZIP reader, ...).
2. rar5_seek_data() in archive_read_support_format_rar5.c, which
unconditionally returns ARCHIVE_FATAL because RAR5 is a
streaming unpacker. This was latent before 3.8.8 because
the read core did not make FATAL sticky; the stickiness
change exposed it.
Both are capability gaps, not stream corruption. ARCHIVE_FATAL
must always be sticky (it means the archive is irrecoverably
damaged), so both sites now return ARCHIVE_FAILED with an error
string instead. ARCHIVE_FAILED is recoverable: capability probes
such as
if (archive_seek_data(a, 0, SEEK_CUR) >= 0) ...
learn that seeking is unavailable while the archive remains
usable for subsequent reads. The sticky-on-genuine-FATAL part of
the original 3.8.8 change is preserved for actual ARCHIVE_FATAL
returns from a format's seek_data() implementation.
The seek_data == NULL branch also reports the condition better: a
format that never registers a seek hook is not illegal use of the
library, so the error is now ARCHIVE_ERRNO_MISC / "Cannot seek
data with this format" instead of ARCHIVE_ERRNO_PROGRAMMER /
"Internal error: No format_seek_data_block function registered".
The rar5 change also matches how the RAR4 reader already reports
the same situation (archive_read_support_format_rar.c:1339
returns ARCHIVE_FAILED for compressed RAR files).
This restores 3.8.7 behaviour for clients that probe seekability
before reading. VLC's skins2 stream extractor
(modules/stream_extractor/archive.c, archive_seek_subentry())
probes with archive_seek_data(a, 0, SEEK_CUR); on a non-seekable
format the poisoned state killed all later archive_read_data()
calls, breaking ZIP-packed .vlt skins on distributions shipping
libarchive 3.8.8.
Tests:
- test_archive_seek_data_unsupported: covers the seek_data==NULL
branch using a ustar archive.
- test_read_format_rar5_seek_data_unsupported: covers the
rar5_seek_data() branch using an existing RAR5 fixture, and
verifies the entry content with verify_data() after the probe.
Both fail on master and pass with this change.