static gboolean fsck_reachable_objects_from_commits (OstreeRepo *repo, GHashTable *commits, gboolean *out_found_corruption, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; GHashTableIter hash_iter; gpointer key, value; gs_unref_hashtable GHashTable *reachable_objects = NULL; guint i; guint mod; guint count; reachable_objects = ostree_repo_traverse_new_reachable (); g_hash_table_iter_init (&hash_iter, commits); 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); g_assert (objtype == OSTREE_OBJECT_TYPE_COMMIT); if (!ostree_repo_traverse_commit_union (repo, checksum, 0, reachable_objects, cancellable, error)) goto out; } count = g_hash_table_size (reachable_objects); mod = count / 10; i = 0; g_hash_table_iter_init (&hash_iter, reachable_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 (!load_and_fsck_one_object (repo, checksum, objtype, out_found_corruption, cancellable, error)) goto out; if (mod == 0 || (i % mod == 0)) g_print ("%u/%u objects\n", i, count); i++; } ret = TRUE; out: return ret; }
static gboolean fsck_reachable_objects_from_commits (OstreeRepo *repo, GHashTable *commits, gboolean *out_found_corruption, GCancellable *cancellable, GError **error) { g_autoptr(GHashTable) reachable_objects = ostree_repo_traverse_new_reachable (); g_autoptr(GHashTable) object_parents = ostree_repo_traverse_new_parents (); GHashTableIter hash_iter; gpointer key, value; g_hash_table_iter_init (&hash_iter, commits); 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); g_assert (objtype == OSTREE_OBJECT_TYPE_COMMIT); if (!ostree_repo_traverse_commit_union_with_parents (repo, checksum, 0, reachable_objects, object_parents, cancellable, error)) return FALSE; } g_auto(GLnxConsoleRef) console = { 0, }; glnx_console_lock (&console); const guint count = g_hash_table_size (reachable_objects); guint i = 0; g_hash_table_iter_init (&hash_iter, reachable_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 (!fsck_one_object (repo, checksum, objtype, object_parents, serialized_key, out_found_corruption, cancellable, error)) return FALSE; i++; glnx_console_progress_n_items ("fsck objects", i, count); } return TRUE; }
static GHashTable * reachable_set_intersect (GHashTable *a, GHashTable *b) { GHashTable *ret = ostree_repo_traverse_new_reachable (); GHashTableIter hashiter; gpointer key, value; g_hash_table_iter_init (&hashiter, a); while (g_hash_table_iter_next (&hashiter, &key, &value)) { GVariant *v = key; if (g_hash_table_contains (b, v)) g_hash_table_insert (ret, g_variant_ref (v), v); } return ret; }
/** * ostree_repo_traverse_commit: * @repo: Repo * @commit_checksum: ASCII SHA256 checksum * @maxdepth: Traverse this many parent commits, -1 for unlimited * @out_reachable: (out) (transfer container) (element-type GVariant GVariant): Set of reachable objects * @cancellable: Cancellable * @error: Error * * Create a new set @out_reachable containing all objects reachable * from @commit_checksum, traversing @maxdepth parent commits. */ gboolean ostree_repo_traverse_commit (OstreeRepo *repo, const char *commit_checksum, int maxdepth, GHashTable **out_reachable, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GHashTable) ret_reachable = ostree_repo_traverse_new_reachable (); if (!ostree_repo_traverse_commit_union (repo, commit_checksum, maxdepth, ret_reachable, cancellable, error)) goto out; ret = TRUE; gs_transfer_out_value (out_reachable, &ret_reachable); out: return ret; }
/** * ostree_repo_prune: * @self: Repo * @flags: Options controlling prune process * @depth: Stop traversal after this many iterations (-1 for unlimited) * @out_objects_total: (out): Number of objects found * @out_objects_pruned: (out): Number of objects deleted * @out_pruned_object_size_total: (out): Storage size in bytes of objects deleted * @cancellable: Cancellable * @error: Error * * Delete content from the repository. By default, this function will * only delete "orphaned" objects not referred to by any commit. This * can happen during a local commit operation, when we have written * content objects but not saved the commit referencing them. * * However, if %OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY is provided, instead * of traversing all commits, only refs will be used. Particularly * when combined with @depth, this is a convenient way to delete * history from the repository. * * Use the %OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE to just determine * statistics on objects that would be deleted, without actually * deleting them. */ gboolean ostree_repo_prune (OstreeRepo *self, OstreeRepoPruneFlags flags, gint depth, gint *out_objects_total, gint *out_objects_pruned, guint64 *out_pruned_object_size_total, GCancellable *cancellable, GError **error) { GHashTableIter hash_iter; gpointer key, value; g_autoptr(GHashTable) objects = NULL; g_autoptr(GHashTable) all_refs = NULL; g_autoptr(GHashTable) reachable = NULL; gboolean refs_only = flags & OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY; reachable = ostree_repo_traverse_new_reachable (); /* This original prune API has fixed logic for traversing refs or all commits * combined with actually deleting content. The newer backend API just does * the deletion. */ if (refs_only) { if (!ostree_repo_list_refs (self, NULL, &all_refs, cancellable, error)) return FALSE; g_hash_table_iter_init (&hash_iter, all_refs); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { const char *checksum = value; g_debug ("Finding objects to keep for commit %s", checksum); if (!ostree_repo_traverse_commit_union (self, checksum, depth, reachable, cancellable, error)) return FALSE; } } if (!ostree_repo_list_objects (self, OSTREE_REPO_LIST_OBJECTS_ALL | OSTREE_REPO_LIST_OBJECTS_NO_PARENTS, &objects, cancellable, error)) return FALSE; if (!refs_only) { 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) continue; g_debug ("Finding objects to keep for commit %s", checksum); if (!ostree_repo_traverse_commit_union (self, checksum, depth, reachable, cancellable, error)) return FALSE; } } { OstreeRepoPruneOptions opts = { flags, reachable }; return repo_prune_internal (self, objects, &opts, out_objects_total, out_objects_pruned, out_pruned_object_size_total, cancellable, error); } }