示例#1
0
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;
}
示例#2
0
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);
示例#3
0
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;
}
示例#4
0
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;
}
示例#5
0
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;
}