From: Michael Tremer Date: Wed, 7 Apr 2021 17:29:51 +0000 (+0000) Subject: archive: Refactor extraction process X-Git-Tag: 0.9.28~1285^2~394 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b1875f5798bd126a078bdb23241f5ab0d6975c15;p=pakfire.git archive: Refactor extraction process Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index 8b133165e..47b954fc2 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -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);