From: Michael Tremer Date: Wed, 7 Apr 2021 11:05:10 +0000 (+0000) Subject: archive: Refactor opening payload X-Git-Tag: 0.9.28~1285^2~409 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6a642ca842aa7beee56ff262679bd3bcc74be411;p=pakfire.git archive: Refactor opening payload This is now using libarchive's internal zero-copy functionality to avoid copying data back and fourth. This should result in faster extraction speed. Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index df3ceaf17..03e87d419 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -92,20 +92,6 @@ struct _PakfireArchiveSignature { int nrefs; }; -struct payload_archive_data { - struct archive* archive; - char buffer[1024 * 1024]; -}; - -static void configure_archive(struct archive* a) { - // All of our packages are tar balls - archive_read_support_format_tar(a); - - // They are compressed using XZ or ZSTD - archive_read_support_filter_xz(a); - archive_read_support_filter_zstd(a); -} - static int archive_open(PakfireArchive archive, struct archive** a) { *a = archive_read_new(); if (!*a) @@ -168,33 +154,59 @@ static int find_archive_entry(struct archive_entry** entry, struct archive* a, c return 1; } -static ssize_t payload_archive_read(struct archive* a, void* client_data, const void** buf) { - struct payload_archive_data* data = client_data; - *buf = data->buffer; +static la_ssize_t pakfire_archive_read_callback(struct archive* a, + void* client_data, const void** buffer) { + struct archive* archive = (struct archive*)client_data; - return archive_read_data(data->archive, data->buffer, sizeof(data->buffer)); -} + size_t len = 0; + off_t offset = 0; -static int payload_archive_close(struct archive* a, void* client_data) { - struct payload_archive_data* data = client_data; + // Try reading the next block (without copying it) + int r = archive_read_data_block(archive, buffer, &len, &offset); - free(data); + switch (r) { + case ARCHIVE_OK: + return len; + + // Return zero to signal that everything was read + case ARCHIVE_EOF: + return 0; - return ARCHIVE_OK; + // Return -1 on any other errors + default: + return -1; + } } -static int payload_archive_open(struct archive** a, struct archive* source_archive) { - *a = archive_read_new(); - configure_archive(*a); +static struct archive* pakfire_archive_open_payload(PakfireArchive archive, struct archive* a) { + // Find the payload + struct archive_entry* entry; + int r = find_archive_entry(&entry, a, PAKFIRE_ARCHIVE_FN_PAYLOAD); + if (r) + return NULL; - struct payload_archive_data* data = calloc(1, sizeof(*data)); - data->archive = source_archive; + // Allocate a new archive object + struct archive* payload = archive_read_new(); + if (!payload) + return NULL; - archive_read_set_callback_data(*a, data); - archive_read_set_read_callback(*a, payload_archive_read); - archive_read_set_close_callback(*a, payload_archive_close); + // All of our packages are tar balls + archive_read_support_format_tar(payload); - return archive_read_open1(*a); + // They are compressed using XZ or ZSTD + archive_read_support_filter_xz(payload); + archive_read_support_filter_zstd(payload); + + // Try opening the payload archive + r = archive_read_open2(payload, a, NULL, pakfire_archive_read_callback, NULL, NULL); + if (r) { + ERROR(archive->pakfire, "Could not open payload archive: %s\n", + archive_error_string(payload)); + archive_read_free(payload); + return NULL; + } + + return payload; } // Checksum Stuff @@ -706,7 +718,10 @@ PAKFIRE_EXPORT char* pakfire_archive_get(PakfireArchive archive, const char* nam } static int archive_extract(PakfireArchive archive, struct archive* a, const char* prefix) { - struct archive_entry* entry; + if (!a) + return EINVAL; + + struct archive_entry* entry = NULL; int r; PakfireFile file; @@ -781,22 +796,6 @@ static int archive_extract(PakfireArchive archive, struct archive* a, const char return r; } -static struct archive* archive_open_payload(struct archive* a) { - struct archive_entry* entry; - int r; - - r = find_archive_entry(&entry, a, PAKFIRE_ARCHIVE_FN_PAYLOAD); - if (r) - return NULL; - - struct archive* payload_archive; - r = payload_archive_open(&payload_archive, a); - if (r) - return NULL; - - return payload_archive; -} - PAKFIRE_EXPORT int pakfire_archive_read(PakfireArchive archive, const char* filename, char** data, size_t* data_size, int flags) { struct archive* a; @@ -810,7 +809,7 @@ PAKFIRE_EXPORT int pakfire_archive_read(PakfireArchive archive, const char* file int use_payload = (flags & PAKFIRE_ARCHIVE_USE_PAYLOAD); if (use_payload) { - pa = archive_open_payload(a); + pa = pakfire_archive_open_payload(archive, a); // Strip leading / from filenames, because the payload does // not have leading slashes. @@ -878,7 +877,7 @@ PAKFIRE_EXPORT int pakfire_archive_extract(PakfireArchive archive, const char* p DEBUG(archive->pakfire, "Extracting %s to %s\n", archive->path, prefix); if (use_payload) - pa = archive_open_payload(a); + pa = pakfire_archive_open_payload(archive, a); r = archive_extract(archive, use_payload ? pa : a, prefix ? prefix : pakfire_get_path(archive->pakfire));