From 53d522480ab6be095241fb70f16f344e01ce25f0 Mon Sep 17 00:00:00 2001 From: Alistair Smith Date: Mon, 17 Aug 2026 20:02:48 -0700 Subject: [PATCH] drop unused libarchive read formats and filters --- .../libarchive/select-registered-only.patch | 116 ++++++++++++++++++ scripts/build/deps/libarchive.ts | 48 +++----- src/install/TarballStream.rs | 17 +-- 3 files changed, 145 insertions(+), 36 deletions(-) create mode 100644 patches/libarchive/select-registered-only.patch diff --git a/patches/libarchive/select-registered-only.patch b/patches/libarchive/select-registered-only.patch new file mode 100644 index 000000000000..f355aff0caa2 --- /dev/null +++ b/patches/libarchive/select-registered-only.patch @@ -0,0 +1,116 @@ +--- a/libarchive/archive_read_set_format.c ++++ b/libarchive/archive_read_set_format.c +@@ -40,9 +40,12 @@ + const char *str; + struct archive_read *a = (struct archive_read *)_a; + +- if ((r1 = archive_read_support_format_by_code(_a, code)) < (ARCHIVE_OK)) +- return r1; +- ++ /* ++ * BUN PATCH: select only among formats the caller already registered. ++ * Upstream first calls archive_read_support_format_by_code(), whose ++ * switch references every reader, so the whole reader set (7zip, rar, ++ * zip, ...) stays linked even though bun only ever registers tar. ++ */ + r1 = r2 = (ARCHIVE_OK); + if (a->format) + r2 = (ARCHIVE_WARN); +@@ -108,7 +111,7 @@ + if (!a->format->name || strcmp(a->format->name, str)) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, +- "Internal error: Unable to set format"); ++ "Format is not registered"); + r1 = (ARCHIVE_FATAL); + } + +--- a/libarchive/archive_read_append_filter.c ++++ b/libarchive/archive_read_append_filter.c +@@ -42,7 +42,12 @@ + struct archive_read_filter *filter; + struct archive_read *a = (struct archive_read *)_a; + +- r2 = (ARCHIVE_OK); ++ /* ++ * BUN PATCH: append only a filter the caller already registered. ++ * Upstream registers it here via archive_read_support_filter_(), ++ * which keeps every filter linked; bun only ever appends gzip. ++ */ ++ r1 = r2 = (ARCHIVE_OK); + switch (code) + { + case ARCHIVE_FILTER_NONE: +@@ -50,19 +55,15 @@ + * NOTE: An initial "NONE" type filter is always set at the end of the + * filter chain. + */ +- r1 = (ARCHIVE_OK); + break; + case ARCHIVE_FILTER_GZIP: + strcpy(str, "gzip"); +- r1 = archive_read_support_filter_gzip(_a); + break; + case ARCHIVE_FILTER_BZIP2: + strcpy(str, "bzip2"); +- r1 = archive_read_support_filter_bzip2(_a); + break; + case ARCHIVE_FILTER_COMPRESS: + strcpy(str, "compress (.Z)"); +- r1 = archive_read_support_filter_compress(_a); + break; + case ARCHIVE_FILTER_PROGRAM: + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, +@@ -70,43 +71,33 @@ + return (ARCHIVE_FATAL); + case ARCHIVE_FILTER_LZMA: + strcpy(str, "lzma"); +- r1 = archive_read_support_filter_lzma(_a); + break; + case ARCHIVE_FILTER_XZ: + strcpy(str, "xz"); +- r1 = archive_read_support_filter_xz(_a); + break; + case ARCHIVE_FILTER_UU: + strcpy(str, "uu"); +- r1 = archive_read_support_filter_uu(_a); + break; + case ARCHIVE_FILTER_RPM: + strcpy(str, "rpm"); +- r1 = archive_read_support_filter_rpm(_a); + break; + case ARCHIVE_FILTER_LZ4: + strcpy(str, "lz4"); +- r1 = archive_read_support_filter_lz4(_a); + break; + case ARCHIVE_FILTER_ZSTD: + strcpy(str, "zstd"); +- r1 = archive_read_support_filter_zstd(_a); + break; + case ARCHIVE_FILTER_LZIP: + strcpy(str, "lzip"); +- r1 = archive_read_support_filter_lzip(_a); + break; + case ARCHIVE_FILTER_LZOP: + strcpy(str, "lzop"); +- r1 = archive_read_support_filter_lzop(_a); + break; + case ARCHIVE_FILTER_LRZIP: + strcpy(str, "lrzip"); +- r1 = archive_read_support_filter_lrzip(_a); + break; + case ARCHIVE_FILTER_GRZIP: + strcpy(str, "grzip"); +- r1 = archive_read_support_filter_grzip(_a); + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, +@@ -127,7 +118,7 @@ + if (!bidder->name || strcmp(bidder->name, str)) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, +- "Internal error: Unable to append filter"); ++ "Filter is not registered"); + return (ARCHIVE_FATAL); + } + diff --git a/scripts/build/deps/libarchive.ts b/scripts/build/deps/libarchive.ts index 0c507dc82872..9c0d9523338f 100644 --- a/scripts/build/deps/libarchive.ts +++ b/scripts/build/deps/libarchive.ts @@ -21,11 +21,13 @@ import { depBuildDir } from "../source.ts"; const LIBARCHIVE_COMMIT = "ded82291ab41d5e355831b96b0e1ff49e24d8939"; -// The unconditional list from libarchive/CMakeLists.txt + the two blake2 -// reference impls (added when libb2 isn't linked, which it never is here). -// All formats/filters compile even though most are stubbed at runtime — -// bun's bindings call archive_read_support_{format,filter}_all, which -// reference every registration symbol. +// The unconditional list from libarchive/CMakeLists.txt, minus the read +// formats/filters bun never registers (it only registers tar/gnutar/gzip, +// and select-registered-only.patch stops set_format/append_filter from +// pulling the rest in). Kept even though unused: format_empty/format_raw +// (archive_match.c), ppmd7 (write_set_format_7zip), filter_program +// (append_filter_program_signature) — dead code that other kept files +// still reference by name. // prettier-ignore const SOURCES = [ "archive_acl", "archive_check_magic", "archive_cmdline", "archive_cryptor", @@ -33,32 +35,18 @@ const SOURCES = [ "archive_entry_link_resolver", "archive_entry_sparse", "archive_entry_stat", "archive_entry_strmode", "archive_entry_xattr", "archive_hmac", "archive_match", "archive_options", "archive_pack_dev", "archive_parse_date", "archive_pathmatch", - "archive_ppmd8", "archive_ppmd7", "archive_random", "archive_rb", "archive_read", + "archive_ppmd7", "archive_random", "archive_rb", "archive_read", "archive_read_add_passphrase", "archive_read_append_filter", "archive_read_data_into_fd", "archive_read_disk_entry_from_file", "archive_read_disk_posix", "archive_read_disk_set_standard_lookup", "archive_read_extract", "archive_read_extract2", "archive_read_open_fd", "archive_read_open_file", "archive_read_open_filename", "archive_read_open_memory", "archive_read_set_format", "archive_read_set_options", - "archive_read_support_filter_all", "archive_read_support_filter_by_code", - "archive_read_support_filter_bzip2", "archive_read_support_filter_compress", - "archive_read_support_filter_gzip", "archive_read_support_filter_grzip", - "archive_read_support_filter_lrzip", "archive_read_support_filter_lz4", - "archive_read_support_filter_lzop", "archive_read_support_filter_none", - "archive_read_support_filter_program", "archive_read_support_filter_rpm", - "archive_read_support_filter_uu", "archive_read_support_filter_xz", - "archive_read_support_filter_zstd", "archive_read_support_format_7zip", - "archive_read_support_format_all", "archive_read_support_format_ar", - "archive_read_support_format_by_code", "archive_read_support_format_cab", - "archive_read_support_format_cpio", "archive_read_support_format_empty", - "archive_read_support_format_iso9660", "archive_read_support_format_lha", - "archive_read_support_format_mtree", "archive_read_support_format_rar", - "archive_read_support_format_rar5", "archive_read_support_format_raw", - "archive_read_support_format_tar", "archive_read_support_format_warc", - "archive_read_support_format_xar", "archive_read_support_format_zip", - "archive_string", "archive_string_sprintf", "archive_time", "archive_util", - "archive_version_details", "archive_virtual", "archive_write", - "archive_write_disk_posix", "archive_write_disk_set_standard_lookup", + "archive_read_support_filter_gzip", "archive_read_support_filter_program", + "archive_read_support_format_empty", "archive_read_support_format_raw", + "archive_read_support_format_tar", "archive_string", "archive_string_sprintf", + "archive_time", "archive_util", "archive_version_details", "archive_virtual", + "archive_write", "archive_write_disk_posix", "archive_write_disk_set_standard_lookup", "archive_write_open_fd", "archive_write_open_file", "archive_write_open_filename", "archive_write_open_memory", "archive_write_add_filter", "archive_write_add_filter_b64encode", "archive_write_add_filter_by_name", @@ -78,9 +66,8 @@ const SOURCES = [ "archive_write_set_format_shar", "archive_write_set_format_ustar", "archive_write_set_format_v7tar", "archive_write_set_format_warc", "archive_write_set_format_xar", "archive_write_set_format_zip", - "archive_write_set_options", "archive_write_set_passphrase", - "filter_fork_posix", "xxhash", - "archive_blake2sp_ref", "archive_blake2s_ref", + "archive_write_set_options", "archive_write_set_passphrase", "filter_fork_posix", + "xxhash", ]; const SOURCES_WIN = [ @@ -103,6 +90,11 @@ export const libarchive: Dependency = { patches: [ "patches/libarchive/archive_write_add_filter_gzip.c.patch", + // archive_read_set_format/append_filter register by code through a + // switch over every reader/filter, which keeps them all linked. Bun + // registers tar/gnutar/gzip itself, so make those calls only select + // an already-registered one. + "patches/libarchive/select-registered-only.patch", // Propagate ARCHIVE_RETRY from the client read callback up through // the gzip filter and tar reader so the worker-thread extract loop // in `bun install` can yield and resume as HTTP chunks arrive. See diff --git a/src/install/TarballStream.rs b/src/install/TarballStream.rs index 7ae9f698469b..81357db9ad40 100644 --- a/src/install/TarballStream.rs +++ b/src/install/TarballStream.rs @@ -616,19 +616,20 @@ impl TarballStream { let archive = lib::ReadArchive::new(); // Bypass bidding entirely: the stream is always gzip → tar, and // bidding would try to read-ahead before any bytes have arrived. + // With patches/libarchive/select-registered-only.patch, + // archive_read_append_filter / archive_read_set_format only select a + // filter/format that was already registered, so register gzip and tar + // first. Tar must also be registered before read_set_options (so the + // option has a slot) and set_format must come after it: libarchive's + // archive_set_format_option() clobbers `a->format` while dispatching, + // and losing the selected format means archive_read_open1() falls + // back to bidding, which fails when the first HTTP chunk is short. // ARCHIVE_FILTER_GZIP = 1, ARCHIVE_FORMAT_TAR = 0x30000. + let _ = archive.read_support_filter_gzip(); // SAFETY: archive is a valid non-null handle from read_new(); FFI call has no other preconditions. if unsafe { lib::archive_read_append_filter(archive.as_mut_ptr(), 1) } != 0 { return Err(crate::Error::Fail); } - // Register tar before read_set_options so the option has a format slot - // to apply to. archive_read_set_format would register it too, but - // libarchive's archive_set_format_option() overwrites `a->format` with - // each slot while dispatching and then writes NULL, so calling - // read_set_options after archive_read_set_format throws the selected - // format away and archive_read_open1() falls back to bidding. Bidding - // reads ahead 512 decompressed bytes and fails with "Unrecognized - // archive format" when the first HTTP chunk is too small for that. let _ = archive.read_support_format_tar(); let _ = archive.read_set_options(c"read_concatenated_archives"); // SAFETY: archive is a valid non-null handle from read_new(); FFI call has no other preconditions.