cr_RepomdRecord * cr_repomd_record_new(const char *type, const char *path) { cr_RepomdRecord *md = g_malloc0(sizeof(*md)); md->chunk = g_string_chunk_new(128); md->type = cr_safe_string_chunk_insert(md->chunk, type); if (path) { gchar *filename = cr_get_filename(path); gchar *location_href = g_strconcat(LOCATION_HREF_PREFIX, filename, NULL); md->location_real = g_string_chunk_insert(md->chunk, path); md->location_href = g_string_chunk_insert(md->chunk, location_href); g_free(location_href); } return md; }
static char * get_checksum(const char *filename, cr_ChecksumType type, cr_Package *pkg, const char *cachedir, GError **err) { GError *tmp_err = NULL; char *checksum = NULL; char *cachefn = NULL; if (cachedir) { // Prepare cache fn char *key; cr_ChecksumCtx *ctx = cr_checksum_new(type, err); if (!ctx) return NULL; if (pkg->siggpg) cr_checksum_update(ctx, pkg->siggpg->data, pkg->siggpg->size, NULL); if (pkg->sigpgp) cr_checksum_update(ctx, pkg->sigpgp->data, pkg->sigpgp->size, NULL); if (pkg->hdrid) cr_checksum_update(ctx, pkg->hdrid, strlen(pkg->hdrid), NULL); key = cr_checksum_final(ctx, err); if (!key) return NULL; cachefn = g_strdup_printf("%s%s-%s-%"G_GINT64_FORMAT"-%"G_GINT64_FORMAT, cachedir, cr_get_filename(pkg->location_href), key, pkg->size_installed, pkg->time_file); free(key); // Try to load checksum FILE *f = fopen(cachefn, "r"); if (f) { char buf[CACHEDCHKSUM_BUFFER_LEN]; size_t readed = fread(buf, 1, CACHEDCHKSUM_BUFFER_LEN, f); if (!ferror(f) && readed > 0) { checksum = g_strndup(buf, readed); } fclose(f); } if (checksum) { g_debug("Cached checksum used: %s: \"%s\"", cachefn, checksum); goto exit; } } // Calculate checksum checksum = cr_checksum_file(filename, type, &tmp_err); if (!checksum) { g_propagate_prefixed_error(err, tmp_err, "Error while checksum calculation: "); goto exit; } // Cache the checksum value if (cachefn && !g_file_test(cachefn, G_FILE_TEST_EXISTS)) { gchar *template = g_strconcat(cachefn, "-XXXXXX", NULL);
int cr_metadata_load_xml(cr_Metadata *md, struct cr_MetadataLocation *ml, GError **err) { int result; GError *tmp_err = NULL; GHashTable *intern_hashtable; // key is checksum (pkgId) cr_HashTableKeyDupAction dupaction = md->dupaction; assert(md); assert(ml); assert(!err || *err == NULL); if (!ml->pri_xml_href) { g_set_error(err, ERR_DOMAIN, CRE_BADARG, "primary.xml file is missing"); return CRE_BADARG; } // Load metadata intern_hashtable = cr_new_metadata_hashtable(); result = cr_load_xml_files(intern_hashtable, ml->pri_xml_href, ml->fil_xml_href, ml->oth_xml_href, md->chunk, md->pkglist_ht, &tmp_err); if (result != CRE_OK) { g_critical("%s: Error encountered while parsing", __func__); g_propagate_prefixed_error(err, tmp_err, "Error encountered while parsing:"); cr_destroy_metadata_hashtable(intern_hashtable); return result; } g_debug("%s: Parsed items: %d", __func__, g_hash_table_size(intern_hashtable)); // Fill user hashtable and use user selected key GHashTableIter iter; gpointer p_key, p_value; GHashTable *ignored_keys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); g_hash_table_iter_init (&iter, intern_hashtable); while (g_hash_table_iter_next (&iter, &p_key, &p_value)) { cr_Package *pkg = (cr_Package *) p_value; cr_Package *epkg; gpointer new_key; switch (md->key) { case CR_HT_KEY_FILENAME: new_key = cr_get_filename(pkg->location_href); break; case CR_HT_KEY_HASH: new_key = pkg->pkgId; break; case CR_HT_KEY_NAME: new_key = pkg->name; break; default: // Well, this SHOULD never happend! // (md->key SHOULD be setted only by cr_metadata_new() // and it SHOULD set only valid key values) g_critical("%s: Unknown hash table key selected", __func__); assert(0); g_set_error(err, ERR_DOMAIN, CRE_ASSERT, "Bad db type"); return CRE_ASSERT; } epkg = g_hash_table_lookup(md->ht, new_key); if (epkg) { // Such key already exists if (dupaction == CR_HT_DUPACT_KEEPFIRST) { g_debug("%s: Key \"%s\" already exists in hashtable - Keeping the first occurrence", __func__, (char *) new_key); } else { if (pkg->time_file != epkg->time_file || pkg->size_package != epkg->size_package || g_strcmp0(pkg->pkgId, epkg->pkgId) || g_strcmp0(cr_get_filename(pkg->location_href), cr_get_filename(epkg->location_href)) ) { // We got a key (checksum, filename, pkg name, ..) // which has a multiple occurences which are different. // Ignore such key g_debug("%s: Key \"%s\" is present multiple times and with " "different values. Ignoring all occurrences. " "[size_package: %"G_GINT64_FORMAT"|%"G_GINT64_FORMAT "; time_file: %"G_GINT64_FORMAT"|%"G_GINT64_FORMAT "; pkgId: %s|%s; basename: %s|%s]", __func__, (gchar *) new_key, pkg->size_package, epkg->size_package, pkg->time_file, epkg->time_file, pkg->pkgId, epkg->pkgId, cr_get_filename(pkg->location_href), cr_get_filename(epkg->location_href)); g_hash_table_insert(ignored_keys, g_strdup((gchar *) new_key), NULL); } } // Remove the package from the iterator anyway g_hash_table_iter_remove(&iter); } else { g_hash_table_insert(md->ht, new_key, p_value); g_hash_table_iter_steal(&iter); } } // Remove ignored_keys from resulting hashtable g_hash_table_iter_init(&iter, ignored_keys); while (g_hash_table_iter_next(&iter, &p_key, &p_value)) { char *key = (gchar *) p_key; g_hash_table_remove(md->ht, key); } // How much items we really use g_debug("%s: Really usable items: %d", __func__, g_hash_table_size(md->ht)); // Cleanup g_hash_table_destroy(ignored_keys); cr_destroy_metadata_hashtable(intern_hashtable); return CRE_OK; }
int cr_repomd_record_rename_file(cr_RepomdRecord *md, GError **err) { int x, len; gchar *location_prefix = NULL; const gchar *location_filename = NULL; gchar *new_location_href; gchar *new_location_real; assert(!err || *err == NULL); if (!md) return CRE_OK; if (!(md->location_real) || !strlen(md->location_real)) { g_debug("Empty locations in repomd record object"); g_set_error(err, CR_REPOMD_RECORD_ERROR, CRE_BADARG, "Empty locations in repomd record object"); return CRE_BADARG; } if (!md->checksum) { g_debug("Record doesn't contain checksum"); g_set_error(err, CR_REPOMD_RECORD_ERROR, CRE_BADARG, "Record doesn't contain checksum"); return CRE_BADARG; } location_filename = md->location_real; x = strlen(md->location_real); for (; x > 0; x--) { if (md->location_real[x] == '/') { location_prefix = g_strndup(md->location_real, x+1); location_filename = cr_get_filename(md->location_real+x+1); break; } } if (!location_prefix) // In case that the location_real doesn't contain '/' location_prefix = g_strdup(""); // Check if the rename is necessary // During update with --keep-all-metadata some files (groupfile, // updateinfo, ..) could already have checksum in filenames if (g_str_has_prefix(location_filename, md->checksum)) { // The filename constains valid checksum g_free(location_prefix); return CRE_OK; } // Skip existing obsolete checksum in the name if there is any len = strlen(location_filename); if (len > 32) { // The filename is long -> it could contains a checksum for (x = 0; x < len; x++) { if (location_filename[x] == '-' && ( x == 32 // Prefix is MD5 checksum || x == 40 // Prefix is SHA1 checksum || x == 64 // Prefix is SHA256 checksum || x == 128 // Prefix is SHA512 checksum )) { location_filename = location_filename + x + 1; break; } } } // Prepare new name new_location_real = g_strconcat(location_prefix, md->checksum, "-", location_filename, NULL); g_free(location_prefix); // Rename file if (g_file_test (new_location_real, G_FILE_TEST_EXISTS)) { if (remove(new_location_real)) { g_critical("%s: Cannot delete old %s", __func__, new_location_real); g_set_error(err, CR_REPOMD_RECORD_ERROR, CRE_IO, "File with name %s already exists and cannot be deleted", new_location_real); g_free(new_location_real); return CRE_IO; } } if (rename(md->location_real, new_location_real)) { g_critical("%s: Cannot rename %s to %s", __func__, md->location_real, new_location_real); g_set_error(err, CR_REPOMD_RECORD_ERROR, CRE_IO, "Cannot rename %s to %s", md->location_real, new_location_real); g_free(new_location_real); return CRE_IO; } // Update locations in repomd record md->location_real = g_string_chunk_insert(md->chunk, new_location_real); new_location_href = g_strconcat(LOCATION_HREF_PREFIX, md->checksum, "-", location_filename, NULL); md->location_href = g_string_chunk_insert(md->chunk, new_location_href); g_free(new_location_real); g_free(new_location_href); return CRE_OK; }
static int primary_pkgcb(cr_Package *pkg, void *cbdata, G_GNUC_UNUSED GError **err) { gboolean store_pkg = TRUE; cr_CbData *cb_data = cbdata; cr_Package *epkg; char *basename = cr_get_filename(pkg->location_href); assert(pkg); assert(pkg->pkgId); if (cb_data->chunk) { // Set pkg internal chunk to NULL, // if global chunk for all packages is used assert(pkg->chunk == cb_data->chunk); pkg->chunk = NULL; } if (cb_data->pkglist_ht && basename) { // If a pkglist was specified, // check if the package should be loaded or not store_pkg = g_hash_table_lookup_extended(cb_data->pkglist_ht, basename, NULL, NULL); } if (store_pkg) { // Check if pkgId is not on the list of blocked Ids if (g_hash_table_lookup_extended(cb_data->ignored_pkgIds, pkg->pkgId, NULL, NULL)) // We should ignore this pkgId (package's hash) store_pkg = FALSE; } if (!store_pkg) { // Drop the currently loaded package cr_package_free(pkg); return CR_CB_RET_OK; } epkg = g_hash_table_lookup(cb_data->ht, pkg->pkgId); if (!epkg) { // Store package into the hashtable pkg->loadingflags |= CR_PACKAGE_FROM_XML; pkg->loadingflags |= CR_PACKAGE_LOADED_PRI; g_hash_table_replace(cb_data->ht, pkg->pkgId, pkg); } else { // Package with the same pkgId (hash) already exists if (epkg->time_file == pkg->time_file && epkg->size_package == pkg->size_package && !g_strcmp0(cr_get_filename(pkg->location_href), basename)) { // The existing package is the same as the current one. // This is ok g_debug("Multiple packages with the same checksum: %s. " "Loading the info only once.", pkg->pkgId); } else { // The existing package is different. We have two different // packages with the same checksum -> drop both of them // and append this checksum to the ignored_pkgIds // XXX: Note that this constrain works only for single repo! // If the same cr_Metadata are loaded from several different // repos, than inter-repo packages with matching checksum // are not checked. g_debug("Multiple different packages (basename, mtime or size " "doesn't match) with the same checksum: %s. " "Ignoring all packages with the checksum.", pkg->pkgId); g_hash_table_remove(cb_data->ht, pkg->pkgId); g_hash_table_replace(cb_data->ignored_pkgIds, g_strdup(pkg->pkgId), NULL); } // Drop the currently loaded package cr_package_free(pkg); return CR_CB_RET_OK; } ++cb_data->pkgKey; pkg->pkgKey = cb_data->pkgKey; return CR_CB_RET_OK; }