drop unused libarchive read formats and filters

Merged
AL
3mo ago
+145-36

Problem

  • bun only ever registers the tar reader (archive_read_support_format_tar / _gnutar) and the gzip read filter (TarballStream.rs, runtime/api/Archive.rs, cli/pack_command.rs, libarchive/lib.rs), but every libarchive reader and read filter still ends up in the binary.
  • The reason is TarballStream::open_archive (src/install/TarballStream.rs), which calls archive_read_set_format and archive_read_append_filter to skip bidding. Upstream, those two functions register the requested format/filter themselves, through archive_read_support_format_by_code() and a switch over every archive_read_support_filter_*(), so one reference from bun keeps the 7zip, rar, zip, iso9660, xz, zstd, ... readers alive through --gc-sections.

Fix

  • patches/libarchive/select-registered-only.patch: archive_read_set_format and archive_read_append_filter no longer register anything; they only select among the formats/filters the caller already registered, and fail with "Format is not registered" / "Filter is not registered" otherwise. The slot lookup loops are upstream's, unchanged.
  • scripts/build/deps/libarchive.ts: drop the reader and read filter sources bun never registers, plus archive_ppmd8 and the blake2 reference implementations that only the zip and rar5 readers used. format_empty, format_raw, ppmd7 and filter_program stay because archive_match.c, archive_write_set_format_7zip.c and archive_read_append_filter.c still reference them by name.
  • TarballStream::open_archive now registers gzip itself before archive_read_append_filter (it already registered tar before archive_read_set_format). The comment there explains the ordering constraint: tar has to be registered before read_set_options, and set_format has to come after it, because archive_set_format_option() writes NULL to a->format when it is done dispatching.
  • Stripped binary size, measured by CI against the build of this branch's merge-base (ff5fc1ffe2, build 100261): linux-x64 -272 KB, linux-aarch64 -320 KB, darwin-aarch64 -259 KB, darwin-x64 -278 KB, windows-x64 -288 KB, windows-aarch64 -292 KB, musl/android/freebsd between -258 KB and -310 KB. The CI size annotation shows a larger number because it compares against a newer main that grew in between.
  • Verified on a debug build of this branch: nm on the binary shows only the tar/gnutar/gzip registration functions plus the three kept-by-reference stubs; test/cli/install/bun-install-streaming-extract.test.ts (the only path that uses the patched functions; with the read_support_filter_gzip() line removed, its streaming case fails with "Fail extracting tarball", so the existing suite covers the new ordering requirement), bun-install-tarball-integrity.test.ts, bun-pack.test.ts, bun-add.test.ts (includes an uncompressed .tar), and test/js/bun/archive.test.ts all pass.

Background

  • libarchive reads an archive through a chain of "read filters" (decompressors such as gzip) feeding a "format" reader (tar, zip, ...). A program registers the candidates it wants with archive_read_support_*(), and on open libarchive "bids": each registered candidate inspects the first bytes and the best match wins.
  • Bidding needs read-ahead, which the streaming bun install extractor cannot provide before the first HTTP chunk arrives, so TarballStream uses archive_read_append_filter(GZIP) and archive_read_set_format(TAR) to pin the chain up front instead. Those are the only two libarchive entry points bun uses that pick a reader by code, and they are what this patch changes.
  • libarchive is built as part of bun's own ninja graph (scripts/build/deps/libarchive.ts lists the source files directly), so removing a file from SOURCES removes it from the link; the patch is what makes that possible without undefined references.