diff options
author | Daniel Alley <dalley@redhat.com> | 2022-06-22 06:48:44 +0300 |
---|---|---|
committer | amatej <matej.ales@seznam.cz> | 2022-06-28 09:27:56 +0300 |
commit | 8fb99cde21ba409ed9d12c40e020038974032ba1 (patch) | |
tree | 9ee71daa9e84af3ab227a4f2a221747af6cc6cf5 | |
parent | 32971377b7fa4e999b039c58b4a0c9ae8c5ac95e (diff) |
createrepo_c shouldn't silently produce duplicate-NEVRA repos
Return an error code and print a message when more than one package have
the same NEVRA.
closes #307
-rw-r--r-- | src/createrepo_c.c | 57 | ||||
-rw-r--r-- | src/dumper_thread.c | 13 | ||||
-rw-r--r-- | src/dumper_thread.h | 4 |
3 files changed, 73 insertions, 1 deletions
diff --git a/src/createrepo_c.c b/src/createrepo_c.c index ff8ce82..ad99ff6 100644 --- a/src/createrepo_c.c +++ b/src/createrepo_c.c @@ -553,6 +553,31 @@ load_old_metadata(cr_Metadata **md, g_hash_table_size(cr_metadata_hashtable(*md))); } +// Sorting function for location_href strings, by length. +// Compatible with g_array_sort() +static int strlensort(gconstpointer a, gconstpointer b) +{ + // Function is supposed to take a double-pointer so unfortunately you cannot pass a + // string-comparison function directly. + gchar **a_ptr = (gchar **)a; + gchar **b_ptr = (gchar **)b; + + int a_len = strnlen(*a_ptr, 4096); + int b_len = strnlen(*b_ptr, 4096); + if (a_len > b_len) + { + return 1; + } + else if (b_len > a_len) + { + return -1; + } + else + { + return 0; + } +} + int main(int argc, char **argv) { @@ -1276,6 +1301,7 @@ main(int argc, char **argv) user_data.repodir_name_len = strlen(in_dir); user_data.task_count = task_count; user_data.package_count = 0; + user_data.nevra_table = g_hash_table_new(g_str_hash, g_str_equal); user_data.skip_stat = cmd_options->skip_stat; user_data.old_metadata = old_metadata; user_data.id_pri = 0; @@ -1290,6 +1316,7 @@ main(int argc, char **argv) user_data.had_errors = 0; user_data.output_pkg_list = output_pkg_list; + g_mutex_init(&(user_data.mutex_nevra_table)); g_mutex_init(&(user_data.mutex_output_pkg_list)); g_mutex_init(&(user_data.mutex_pri)); g_mutex_init(&(user_data.mutex_fil)); @@ -1310,9 +1337,36 @@ main(int argc, char **argv) // Wait until pool is finished g_thread_pool_free(pool, FALSE, TRUE); + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init(&iter, user_data.nevra_table); + while (g_hash_table_iter_next(&iter, &key, &value)) + { + gchar *nevra = (gchar *) key; + GArray *locations = (GArray *) value; + if (locations->len > 1) { + g_warning("Package '%s' has duplicate metadata entries, only one should exist", nevra); + + g_array_sort(locations, strlensort); + + for (int i=0; i<locations->len; i++) { + g_warning(" Sourced from location: \'%s\'", g_array_index(locations, gchar *, i)); + } + } + + g_hash_table_iter_steal(&iter); + g_free(nevra); + for (int i = 0; i < locations->len; i++) { + g_free(g_array_index(locations, gchar *, i)); + } + g_array_free(locations, TRUE); + } + g_hash_table_destroy(user_data.nevra_table); + // if there were any errors, exit nonzero if ( user_data.had_errors ) { - exit_val = 2; + exit_val = 2; } g_message("Pool finished%s", (user_data.had_errors ? " with errors" : "")); @@ -1453,6 +1507,7 @@ main(int argc, char **argv) } g_queue_free(user_data.buffer); + g_mutex_clear(&(user_data.mutex_nevra_table)); g_mutex_clear(&(user_data.mutex_output_pkg_list)); g_mutex_clear(&(user_data.mutex_pri)); g_mutex_clear(&(user_data.mutex_fil)); diff --git a/src/dumper_thread.c b/src/dumper_thread.c index c94f26e..b949ffb 100644 --- a/src/dumper_thread.c +++ b/src/dumper_thread.c @@ -551,6 +551,19 @@ cr_dumper_thread(gpointer data, gpointer user_data) } #endif + // Allow checking that the same package (NEVRA) isn't present multiple times in the metadata + // Keep a hashtable of NEVRA mapped to an array-list of location_href values + g_mutex_lock(&(udata->mutex_nevra_table)); + gchar *nevra = cr_package_nevra(pkg); + GArray *pkg_locations = g_hash_table_lookup(udata->nevra_table, nevra); + if (!pkg_locations) { + pkg_locations = g_array_new(FALSE, TRUE, sizeof(gchar *)); + g_hash_table_insert(udata->nevra_table, nevra, pkg_locations); + } + gchar *location = g_strdup(pkg->location_href); + g_array_append_val(pkg_locations, location); + g_mutex_unlock(&(udata->mutex_nevra_table)); + // Buffering stuff g_mutex_lock(&(udata->mutex_buffer)); diff --git a/src/dumper_thread.h b/src/dumper_thread.h index 60f984d..fb815cb 100644 --- a/src/dumper_thread.h +++ b/src/dumper_thread.h @@ -69,6 +69,10 @@ struct UserData { long task_count; // Total number of task to process long package_count; // Total number of packages processed + // Duplicate package error checking + GMutex mutex_nevra_table; // Mutex for the table of NEVRAs + GHashTable *nevra_table; // Table of NEVRAs, with a list of location_href as key + // Update stuff gboolean skip_stat; // Skip stat() while updating cr_Metadata *old_metadata; // Loaded metadata |