From: Michael Tremer Date: Wed, 15 Mar 2023 11:30:41 +0000 (+0000) Subject: compress: Resolve hardlinks when writing archives X-Git-Tag: 0.9.29~314 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=377c9b984bd29475441a506977dd75542c61398e;p=pakfire.git compress: Resolve hardlinks when writing archives Fixes: #13014 Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/compress.c b/src/libpakfire/compress.c index b956e2aec..8a5d793ba 100644 --- a/src/libpakfire/compress.c +++ b/src/libpakfire/compress.c @@ -848,6 +848,9 @@ struct pakfire_compress { // The archive to write to struct archive* archive; + // Resolver for hardlinks + struct archive_entry_linkresolver* linkresolver; + // The filelist of all files to write struct pakfire_filelist* filelist; @@ -900,25 +903,10 @@ static int pakfire_compress_progressbar_create(struct pakfire_progressbar** prog return 0; } -static int __pakfire_compress(struct pakfire* pakfire, struct pakfire_file* file, void* p) { - struct archive_entry* entry = NULL; +static int __pakfire_compress_entry(struct pakfire* pakfire, struct pakfire_file* file, + struct pakfire_compress* data, struct archive_entry* entry) { FILE* f = NULL; - int r = 1; - - struct pakfire_compress* data = (struct pakfire_compress*)p; - - // Fetch type - const mode_t type = pakfire_file_get_type(file); - - // Fetch the filelist - const size_t size = pakfire_file_get_size(file); - - // Generate file metadata into an archive entry - entry = pakfire_file_archive_entry(file, data->digests); - if (!entry) { - r = 1; - goto ERROR; - } + int r; // Write the header r = archive_write_header(data->archive, entry); @@ -928,8 +916,8 @@ static int __pakfire_compress(struct pakfire* pakfire, struct pakfire_file* file goto ERROR; } - // Copy the data of regular files - if (type == S_IFREG) { + // Copy the data if there is any + if (archive_entry_size(entry)) { // Open the file f = pakfire_file_open(file); if (!f) { @@ -948,15 +936,81 @@ static int __pakfire_compress(struct pakfire* pakfire, struct pakfire_file* file if (r) goto ERROR; +ERROR: + if (f) + fclose(f); + + return r; +} + +static int __pakfire_compress(struct pakfire* pakfire, struct pakfire_file* file, void* p) { + struct archive_entry* entry = NULL; + struct archive_entry* sparse_entry = NULL; + int r = 1; + + struct pakfire_compress* data = (struct pakfire_compress*)p; + + // Fetch the file size + const size_t size = pakfire_file_get_size(file); + + // Generate file metadata into an archive entry + entry = pakfire_file_archive_entry(file, data->digests); + if (!entry) { + r = 1; + goto ERROR; + } + + // Perform search for hardlinks + archive_entry_linkify(data->linkresolver, &entry, &sparse_entry); + + // Write the main entry + if (entry) { + r = __pakfire_compress_entry(pakfire, file, data, entry); + if (r) + goto ERROR; + } + + // Write the sparse entry + if (sparse_entry) { + r = __pakfire_compress_entry(pakfire, file, data, sparse_entry); + if (r) + goto ERROR; + } + + // Query the link resolver for any more entries + for (;;) { + // Free the entry + if (entry) { + archive_entry_free(entry); + entry = NULL; + } + + // Free the sparse entry + if (sparse_entry) { + archive_entry_free(sparse_entry); + sparse_entry = NULL; + } + + // Fetch the next entry + archive_entry_linkify(data->linkresolver, &entry, &sparse_entry); + if (!entry) + break; + + // Write the entry to the archive + r = __pakfire_compress_entry(pakfire, file, data, entry); + if (r) + goto ERROR; + } + // Update the progressbar if (data->progressbar) pakfire_progressbar_increment(data->progressbar, size); ERROR: - if (f) - fclose(f); if (entry) archive_entry_free(entry); + if (sparse_entry) + archive_entry_free(sparse_entry); return r; } @@ -989,6 +1043,16 @@ int pakfire_compress(struct pakfire* pakfire, struct archive* archive, pakfire_progressbar_start(data.progressbar, size); } + // Setup the link resolver + data.linkresolver = archive_entry_linkresolver_new(); + if (!data.linkresolver) { + ERROR(pakfire, "Could not setup link resolver: m\n"); + goto ERROR; + } + + // Set the link resolver strategy + archive_entry_linkresolver_set_strategy(data.linkresolver, archive_format(archive)); + // Walk through the entire filelist r = pakfire_filelist_walk(filelist, __pakfire_compress, &data); if (r) @@ -1001,6 +1065,8 @@ int pakfire_compress(struct pakfire* pakfire, struct archive* archive, ERROR: if (data.progressbar) pakfire_progressbar_unref(data.progressbar); + if (data.linkresolver) + archive_entry_linkresolver_free(data.linkresolver); return r; }