]> git.ipfire.org Git - pakfire.git/commitdiff
archive: Refactor opening payload
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 7 Apr 2021 11:05:10 +0000 (11:05 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 7 Apr 2021 11:05:10 +0000 (11:05 +0000)
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 <michael.tremer@ipfire.org>
src/libpakfire/archive.c

index df3ceaf1711c63864737fbb510346c480763d0b6..03e87d4194394483853c289026e3daca09a8e9b4 100644 (file)
@@ -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));