From: Michael Tremer Date: Sat, 8 Feb 2025 10:55:57 +0000 (+0000) Subject: archive writer: Configure libarchive depending on the format X-Git-Tag: 0.9.30~81 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5c19f150cef47bcd736a223cad9cdafaec150178;p=pakfire.git archive writer: Configure libarchive depending on the format Signed-off-by: Michael Tremer --- diff --git a/src/pakfire/archive_writer.c b/src/pakfire/archive_writer.c index c734ffc1..2e3fdf83 100644 --- a/src/pakfire/archive_writer.c +++ b/src/pakfire/archive_writer.c @@ -22,7 +22,12 @@ #include #include +// libarchive +#include +#include + #include +#include struct pakfire_archive_writer { struct pakfire_ctx* ctx; @@ -34,11 +39,162 @@ struct pakfire_archive_writer { // Format pakfire_archive_writer_format format; + // Container + enum pakfire_archive_writer_container { + PAKFIRE_CONTAINER_PAX, + } container; + + // Compression + enum pakfire_archive_writer_compression { + PAKFIRE_COMPRESSION_NONE, + PAKFIRE_COMPRESSION_ZSTD, + } compression; + unsigned int compression_level; + // File Handle FILE* f; + + // Archive + struct archive* archive; }; +/* + * This function configures this object depending on the format. + */ +static int pakfire_archive_writer_setup_format( + struct pakfire_archive_writer* self, pakfire_archive_writer_format format) { + switch (format) { + // The Pakfire Archive Format + case PAKFIRE_FORMAT_ARCHIVE: + // We use the PAX tar format + self->container = PAKFIRE_CONTAINER_PAX; + + // We use Zstandard compression + self->compression = PAKFIRE_COMPRESSION_ZSTD; + + // Use some good compression + self->compression_level = 20; + break; + + // Fail on invalid inputs + default: + ERROR(self->ctx, "Invalid archive format\n"); + return -EINVAL; + } + + return 0; +} + +static int pakfire_archive_writer_setup_archive(struct pakfire_archive_writer* self) { + char value[64]; + int r; + + // Open a new archive + self->archive = archive_write_new(); + if (!self->archive) { + ERROR(self->ctx, "archive_write_new() failed\n"); + return -ENOTSUP; + } + + // Set the container format + switch (self->container) { + case PAKFIRE_CONTAINER_PAX: + // Use the PAX format + r = archive_write_set_format_pax(self->archive); + if (r) { + ERROR(self->ctx, "Could not set format to PAX: %s\n", + archive_error_string(self->archive)); + return -ENOTSUP; + } + + // Store any extended attributes in the SCHILY headers + r = archive_write_set_format_option(self->archive, "pax", "xattrheader", "SCHILY"); + if (r) { + ERROR(self->ctx, "Could not set xattrheader option: %s\n", + archive_error_string(self->archive)); + return -ENOTSUP; + } + break; + } + + // Set the compression + switch (self->compression) { + case PAKFIRE_COMPRESSION_NONE: + break; + + // Zstandard + case PAKFIRE_COMPRESSION_ZSTD: + r = archive_write_add_filter_zstd(self->archive); + if (r) { + ERROR(self->ctx, "Could not enable Zstandard compression: %s\n", + archive_error_string(self->archive)); + return -ENOTSUP; + } + + // Do not pad the last block + archive_write_set_bytes_in_last_block(self->archive, 1); + +#if ARCHIVE_VERSION_NUMBER >= 3007002 + // Enable long mode (supported from libarchive >= 3.7.2) + r = archive_write_set_filter_option(self->archive, NULL, "long", "31"); + if (r) { + ERROR(self->ctx, "Failed to enable Zstandard long mode: %s\n", + archive_error_string(self->archive)); + return -ENOTSUP; + } +#endif /* ARCHIVE_VERSION_NUMBER >= 3007002 */ + +#if ARCHIVE_VERSION_NUMBER >= 3006000 + // Fetch numbers of processors + long processors = sysconf(_SC_NPROCESSORS_ONLN); + + if (processors > 1) { + r = pakfire_string_format(value, "%ld", processors); + if (r) + return r; + + // Try using multiple threads + r = archive_write_set_filter_option(self->archive, NULL, "threads", value); + if (r) { + ERROR(self->ctx, "Could not enable %ld threads for compression: %s\n", + processors, archive_error_string(self->archive)); + return -ENOTSUP; + } + } +#endif + break; + } + + // Set compression level + if (self->compression_level) { + // Format the value + r = pakfire_string_format(value, "%u", self->compression_level); + if (r < 0) + return r; + + // Set the value + r = archive_write_set_filter_option(self->archive, NULL, "compression-level", value); + if (r) { + ERROR(self->ctx, "Could not set compression level %s: %s\n", + value, archive_error_string(self->archive)); + return -ENOTSUP; + } + } + + // Write archive to f + r = archive_write_open_FILE(self->archive, self->f); + if (r) { + ERROR(self->ctx, "archive_write_open_FILE() failed: %s\n", + archive_error_string(self->archive)); + return -ENOTSUP; + } + + return 0; +} + static void pakfire_archive_writer_free(struct pakfire_archive_writer* self) { + if (self->archive) + archive_write_free(self->archive); if (self->pakfire) pakfire_unref(self->pakfire); if (self->ctx) @@ -65,21 +221,19 @@ int pakfire_archive_writer_create(struct pakfire_archive_writer** writer, // Initialize the reference counter self->nrefs = 1; - // Store the format - switch (format) { - case PAKFIRE_FORMAT_ARCHIVE: - self->format = format; - break; - - default: - ERROR(self->ctx, "Invalid archive format\n"); - r = -EINVAL; - goto ERROR; - } - // Store the file handle self->f = f; + // Setup format + r = pakfire_archive_writer_setup_format(self, format); + if (r < 0) + goto ERROR; + + // Setup archive + r = pakfire_archive_writer_setup_archive(self); + if (r < 0) + goto ERROR; + // Return the pointer *writer = self; return 0;