1 Commits
Author SHA1 Message Date
Jin 79b06edf6e archive_read: don't poison archive when seek is unsupported (fixes #3323)
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.
2026-07-28 00:30:34 +08:00