]> git.ipfire.org Git - pakfire.git/commitdiff
archive: Refactor extraction process
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 7 Apr 2021 17:29:51 +0000 (17:29 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 7 Apr 2021 17:29:51 +0000 (17:29 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/archive.c

index 8b133165e5a0b4bc63a0e0d2fc6cc1ba26a86c2a..47b954fc2ecfac5f4fd325fd1359632ed785a7f4 100644 (file)
@@ -545,11 +545,36 @@ static int pakfire_archive_parse_entry_scriptlet(PakfireArchive archive,
        return 0;
 }
 
+static int pakfire_archive_walk_entries(PakfireArchive archive, struct archive* a,
+               int (*callback)(PakfireArchive archive, struct archive* a, struct archive_entry* e, void* data),
+               void* data) {
+       struct archive_entry* e = NULL;
+
+       // Walk through the archive
+       while (1) {
+               int r = archive_read_next_header(a, &e);
+
+               // Return OK when we reached the end of the archive
+               if (r == ARCHIVE_EOF)
+                       return ARCHIVE_OK;
+
+               // Raise any other errors
+               else if (r)
+                       return r;
+
+               // Run callback
+               r = callback(archive, a, e, data);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
 static int pakfire_archive_walk(PakfireArchive archive,
                int (*callback)(PakfireArchive archive, struct archive* a, struct archive_entry* e, void* data),
                void* data) {
        struct archive* a;
-       struct archive_entry* e;
 
        // Open the archive file
        int r = archive_open(archive, &a);
@@ -557,16 +582,7 @@ static int pakfire_archive_walk(PakfireArchive archive,
                return r;
 
        // Walk through the archive
-       while (1) {
-               r = archive_read_next_header(a, &e);
-               if (r)
-                       break;
-
-               // Run callback
-               r = callback(archive, a, e, data);
-               if (r)
-                       break;
-       }
+       r = pakfire_archive_walk_entries(archive, a, callback, data);
 
        // Close the archive
        archive_read_free(a);
@@ -697,85 +713,6 @@ PAKFIRE_EXPORT char* pakfire_archive_get(PakfireArchive archive, const char* nam
        return pakfire_parser_get(archive->parser, namespace, key);
 }
 
-static int archive_extract(PakfireArchive archive, struct archive* a, const char* prefix) {
-       if (!a)
-               return EINVAL;
-
-       struct archive_entry* entry = NULL;
-       int r;
-       PakfireFile file;
-
-       // Reset the filelist
-       if (archive->filelist)
-               pakfire_filelist_clear(archive->filelist);
-
-       struct archive* writer = pakfire_make_archive_disk_writer(archive->pakfire);
-       if (!writer)
-               return 1;
-
-       for (;;) {
-               r = archive_read_next_header(a, &entry);
-
-               // Reached the end of the archive.
-               if (r == ARCHIVE_EOF) {
-                       r = ARCHIVE_OK;
-                       break;
-               }
-
-               // Create a new file object
-               r = pakfire_file_create(&file, archive->pakfire);
-               if (r)
-                       return r;
-
-               // Import attributes
-               r = pakfire_file_copy_archive_entry(file, entry);
-               if (r)
-                       return r;
-
-               const char* archive_pathname = archive_entry_pathname(entry);
-               size_t size = archive_entry_size(entry);
-
-               // Prepend the prefix to the path the file is extracted to.
-               char* pathname = pakfire_path_join(prefix, archive_pathname);
-               archive_entry_set_pathname(entry, pathname);
-
-               DEBUG(archive->pakfire, "Extracting %s (%zu bytes)\n", pathname, size);
-               free(pathname);
-
-               // Update hardlink targets
-               const char* hardlink = archive_entry_hardlink(entry);
-               if (hardlink) {
-                       // Make new hardlink target relative to prefix
-                       char* h = pakfire_path_join(prefix, hardlink);
-
-                       // Update the entry
-                       archive_entry_set_hardlink(entry, h);
-                       free(h);
-               }
-
-               // Create file & payload
-               r = archive_read_extract2(a, entry, writer);
-               if (r != ARCHIVE_OK) {
-                       ERROR(archive->pakfire, "Could not extract file /%s: %s\n",
-                               archive_pathname, archive_error_string(writer));
-                       pakfire_file_unref(file);
-                       break;
-               }
-
-               // Append file to filelist
-               r = pakfire_filelist_append(archive->filelist, file);
-               if (r)
-                       break;
-
-               pakfire_file_unref(file);
-       }
-
-       archive_write_close(writer);
-       archive_write_free(writer);
-
-       return r;
-}
-
 PAKFIRE_EXPORT int pakfire_archive_read(PakfireArchive archive, const char* filename,
                char** data, size_t* data_size, int flags) {
        struct archive* a;
@@ -844,9 +781,82 @@ PAKFIRE_EXPORT char* pakfire_archive_extraction_path(PakfireArchive archive, con
        return prefix;
 }
 
+struct pakfire_archive_extractor {
+       struct archive* writer;
+       const char* prefix;
+       PakfireFilelist filelist;
+};
+
+static int pakfire_archive_extract_entry(PakfireArchive archive,
+               struct archive* a, struct archive_entry* entry, void* data) {
+       struct pakfire_archive_extractor* extractor = (struct pakfire_archive_extractor*)data;
+
+       PakfireFile file = NULL;
+       char* buffer;
+       int r = 1;
+
+       // Create a new file object if there is a filelist
+       if (extractor->filelist) {
+               r = pakfire_file_create(&file, archive->pakfire);
+               if (r)
+                       goto ERROR;
+
+               // Import attributes
+               r = pakfire_file_copy_archive_entry(file, entry);
+               if (r)
+                       goto ERROR;
+
+               // Append it to the filelist
+               r = pakfire_filelist_append(extractor->filelist, file);
+               if (r)
+                       goto ERROR;
+       }
+
+       // Fetch the paths
+       const char* path = archive_entry_pathname(entry);
+
+       DEBUG(archive->pakfire, "Extracting %s\n", path);
+
+       // Prepend the prefix
+       if (extractor->prefix) {
+               buffer = pakfire_path_join(extractor->prefix, path);
+               if (!buffer)
+                       goto ERROR;
+
+               archive_entry_set_pathname(entry, buffer);
+               free(buffer);
+
+               // Update hardlink destination
+               const char* link = archive_entry_hardlink(entry);
+               if (link) {
+                       buffer = pakfire_path_join(extractor->prefix, link);
+                       if (!buffer)
+                               goto ERROR;
+
+                       archive_entry_set_hardlink(entry, buffer);
+                       free(buffer);
+               }
+       }
+
+       // Create file & extract payload
+       r = archive_read_extract2(a, entry, extractor->writer);
+       if (r != ARCHIVE_OK) {
+               ERROR(archive->pakfire, "Could not extract file /%s: %s\n",
+                       path, archive_error_string(extractor->writer));
+               goto ERROR;
+       }
+
+ERROR:
+       if (file)
+               pakfire_file_unref(file);
+
+       return r;
+}
+
 PAKFIRE_EXPORT int pakfire_archive_extract(PakfireArchive archive, const char* prefix, int flags) {
-       struct archive* a;
+       struct archive* a = NULL;
        struct archive* payload = NULL;
+       struct archive* writer = NULL;
 
        // Use default path if nothing is set
        if (!prefix)
@@ -866,10 +876,23 @@ PAKFIRE_EXPORT int pakfire_archive_extract(PakfireArchive archive, const char* p
                        goto ERROR;
        }
 
+       // Allocate writer
+       writer = pakfire_make_archive_disk_writer(archive->pakfire);
+       if (!writer)
+               goto ERROR;
+
+       struct pakfire_archive_extractor extractor = {
+               .writer = writer,
+               .prefix = prefix,
+       };
+
        // Extract everything
-       r = archive_extract(archive, (payload) ? payload : a, prefix);
+       r = pakfire_archive_walk_entries(archive, (payload) ? payload : a,
+               pakfire_archive_extract_entry, &extractor);
 
 ERROR:
+       if (writer)
+               archive_write_free(writer);
        if (payload)
                archive_read_free(payload);
        archive_read_free(a);