gboolean ostree_builtin_fsck (int argc, char **argv, GFile *repo_path, GError **error) { GOptionContext *context; OtFsckData data; gboolean ret = FALSE; GCancellable *cancellable = NULL; GHashTableIter hash_iter; gpointer key, value; ot_lobj OstreeRepo *repo = NULL; ot_lhash GHashTable *objects = NULL; ot_lhash GHashTable *commits = NULL; context = g_option_context_new ("- Check the repository for consistency"); g_option_context_add_main_entries (context, options, NULL); if (!g_option_context_parse (context, &argc, &argv, error)) goto out; repo = ostree_repo_new (repo_path); if (!ostree_repo_check (repo, error)) goto out; memset (&data, 0, sizeof (data)); data.repo = repo; g_print ("Enumerating objects...\n"); if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_ALL, &objects, cancellable, error)) goto out; commits = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, (GDestroyNotify)g_variant_unref, NULL); g_hash_table_iter_init (&hash_iter, objects); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { GVariant *serialized_key = key; const char *checksum; OstreeObjectType objtype; ostree_object_name_deserialize (serialized_key, &checksum, &objtype); if (objtype == OSTREE_OBJECT_TYPE_COMMIT) g_hash_table_insert (commits, g_variant_ref (serialized_key), serialized_key); } g_clear_pointer (&objects, (GDestroyNotify) g_hash_table_unref); g_print ("Verifying content integrity of %u commit objects...\n", (guint)g_hash_table_size (commits)); if (!fsck_reachable_objects_from_commits (&data, commits, cancellable, error)) goto out; ret = TRUE; out: if (context) g_option_context_free (context); return ret; }
gboolean ostree_builtin_fsck (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) { g_autoptr(OstreeRepo) repo = NULL; gboolean found_corruption = FALSE; g_autoptr(GOptionContext) context = g_option_context_new (""); if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) return FALSE; if (!opt_quiet) g_print ("Validating refs...\n"); /* Validate that the commit for each ref is available */ g_autoptr(GHashTable) all_refs = NULL; if (!ostree_repo_list_refs (repo, NULL, &all_refs, cancellable, error)) return FALSE; GHashTableIter hash_iter; gpointer key, value; g_hash_table_iter_init (&hash_iter, all_refs); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { const char *refspec = key; const char *checksum = value; g_autofree char *ref_name = NULL; if (!ostree_parse_refspec (refspec, NULL, &ref_name, error)) return FALSE; if (!fsck_commit_for_ref (repo, checksum, NULL, ref_name, &found_corruption, cancellable, error)) return FALSE; } if (!opt_quiet) g_print ("Validating refs in collections...\n"); g_autoptr(GHashTable) all_collection_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ if (!ostree_repo_list_collection_refs (repo, NULL, &all_collection_refs, OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, cancellable, error)) return FALSE; g_hash_table_iter_init (&hash_iter, all_collection_refs); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { const OstreeCollectionRef *ref = key; if (!fsck_commit_for_ref (repo, value, ref->collection_id, ref->ref_name, &found_corruption, cancellable, error)) return FALSE; } if (!opt_quiet) g_print ("Enumerating objects...\n"); g_autoptr(GHashTable) objects = NULL; if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_ALL, &objects, cancellable, error)) return FALSE; g_autoptr(GHashTable) commits = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, (GDestroyNotify)g_variant_unref, NULL); g_autoptr(GPtrArray) tombstones = NULL; if (opt_add_tombstones) tombstones = g_ptr_array_new_with_free_func (g_free); if (opt_verify_back_refs) opt_verify_bindings = TRUE; guint n_partial = 0; g_hash_table_iter_init (&hash_iter, objects); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { GVariant *serialized_key = key; const char *checksum; OstreeObjectType objtype; OstreeRepoCommitState commitstate = 0; g_autoptr(GVariant) commit = NULL; ostree_object_name_deserialize (serialized_key, &checksum, &objtype); if (objtype == OSTREE_OBJECT_TYPE_COMMIT) { if (!ostree_repo_load_commit (repo, checksum, &commit, &commitstate, error)) return FALSE; /* If requested, check that all the refs listed in the ref-bindings * for this commit resolve back to this commit. */ if (opt_verify_back_refs) { g_autoptr(GVariant) metadata = g_variant_get_child_value (commit, 0); const char *collection_id = NULL; if (!g_variant_lookup (metadata, OSTREE_COMMIT_META_KEY_COLLECTION_BINDING, "&s", &collection_id)) collection_id = NULL; g_autofree const char **refs = NULL; if (g_variant_lookup (metadata, OSTREE_COMMIT_META_KEY_REF_BINDING, "^a&s", &refs)) { for (const char **iter = refs; *iter != NULL; ++iter) { g_autofree char *checksum_for_ref = NULL; if (collection_id != NULL) { const OstreeCollectionRef collection_ref = { (char *) collection_id, (char *) *iter }; if (!ostree_repo_resolve_collection_ref (repo, &collection_ref, TRUE, OSTREE_REPO_RESOLVE_REV_EXT_NONE, &checksum_for_ref, cancellable, error)) return FALSE; } else { if (!ostree_repo_resolve_rev (repo, *iter, TRUE, &checksum_for_ref, error)) return FALSE; } if (checksum_for_ref == NULL) { if (collection_id != NULL) return glnx_throw (error, "Collection–ref (%s, %s) in bindings for commit %s does not exist", collection_id, *iter, checksum); else return glnx_throw (error, "Ref ‘%s’ in bindings for commit %s does not exist", *iter, checksum); } else if (g_strcmp0 (checksum_for_ref, checksum) != 0) { if (collection_id != NULL) return glnx_throw (error, "Collection–ref (%s, %s) in bindings for commit %s does not resolve to that commit", collection_id, *iter, checksum); else return glnx_throw (error, "Ref ‘%s’ in bindings for commit %s does not resolve to that commit", *iter, checksum); } } } } if (opt_add_tombstones) { GError *local_error = NULL; g_autofree char *parent = ostree_commit_get_parent (commit); if (parent) { g_autoptr(GVariant) parent_commit = NULL; if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, parent, &parent_commit, &local_error)) { if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { g_ptr_array_add (tombstones, g_strdup (checksum)); g_clear_error (&local_error); } else { g_propagate_error (error, local_error); return FALSE; } } } } if (commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL) n_partial++; else g_hash_table_add (commits, g_variant_ref (serialized_key)); } } g_clear_pointer (&objects, (GDestroyNotify) g_hash_table_unref); if (!opt_quiet) g_print ("Verifying content integrity of %u commit objects...\n", (guint)g_hash_table_size (commits)); if (!fsck_reachable_objects_from_commits (repo, commits, &found_corruption, cancellable, error)) return FALSE; if (opt_add_tombstones) { guint i; if (tombstones->len) { if (!ot_enable_tombstone_commits (repo, error)) return FALSE; } for (i = 0; i < tombstones->len; i++) { const char *checksum = tombstones->pdata[i]; g_print ("Adding tombstone for commit %s\n", checksum); if (!ostree_repo_delete_object (repo, OSTREE_OBJECT_TYPE_COMMIT, checksum, cancellable, error)) return FALSE; } } else if (n_partial > 0) { g_print ("%u partial commits not verified\n", n_partial); } if (found_corruption) return glnx_throw (error, "Repository corruption encountered"); return TRUE; }
gboolean ostree_builtin_fsck (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; GOptionContext *context; GHashTableIter hash_iter; gpointer key, value; gboolean found_corruption = FALSE; gs_unref_hashtable GHashTable *objects = NULL; gs_unref_hashtable GHashTable *commits = NULL; context = g_option_context_new ("- Check the repository for consistency"); g_option_context_add_main_entries (context, options, NULL); if (!g_option_context_parse (context, &argc, &argv, error)) goto out; if (!opt_quiet) g_print ("Enumerating objects...\n"); if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_ALL, &objects, cancellable, error)) goto out; commits = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, (GDestroyNotify)g_variant_unref, NULL); g_hash_table_iter_init (&hash_iter, objects); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { GVariant *serialized_key = key; const char *checksum; OstreeObjectType objtype; ostree_object_name_deserialize (serialized_key, &checksum, &objtype); if (objtype == OSTREE_OBJECT_TYPE_COMMIT) g_hash_table_insert (commits, g_variant_ref (serialized_key), serialized_key); } g_clear_pointer (&objects, (GDestroyNotify) g_hash_table_unref); if (!opt_quiet) g_print ("Verifying content integrity of %u commit objects...\n", (guint)g_hash_table_size (commits)); if (!fsck_reachable_objects_from_commits (repo, commits, &found_corruption, cancellable, error)) goto out; if (found_corruption) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Repository corruption encountered"); goto out; } ret = TRUE; out: if (context) g_option_context_free (context); return ret; }