summaryrefslogtreecommitdiff
path: root/src/libostree/ostree-repo-traverse.c
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2013-07-09 19:59:39 -0400
committerColin Walters <walters@verbum.org>2013-07-09 19:59:39 -0400
commit2aa0251b1b3dfc1bf06840c8e1fa35e59534c9e2 (patch)
tree4d842198a8546711e422d0929bb521a188b4e028 /src/libostree/ostree-repo-traverse.c
parentcb6b69616c7e452599b9e49edf73fcd893fb887e (diff)
downloadostree-2aa0251b1b3dfc1bf06840c8e1fa35e59534c9e2.tar.gz
libostree: Rename ostree-traverse.h into OstreeRepo namespace
This operates on the repo, it might as well be methods on it.
Diffstat (limited to 'src/libostree/ostree-repo-traverse.c')
-rw-r--r--src/libostree/ostree-repo-traverse.c227
1 files changed, 227 insertions, 0 deletions
diff --git a/src/libostree/ostree-repo-traverse.c b/src/libostree/ostree-repo-traverse.c
new file mode 100644
index 00000000..70b22d7a
--- /dev/null
+++ b/src/libostree/ostree-repo-traverse.c
@@ -0,0 +1,227 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters@verbum.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters@verbum.org>
+ */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include "ostree.h"
+#include "otutil.h"
+
+GHashTable *
+ostree_repo_traverse_new_reachable (void)
+{
+ return g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
+ (GDestroyNotify)g_variant_unref, NULL);
+}
+
+static gboolean
+traverse_dirtree_internal (OstreeRepo *repo,
+ const char *dirtree_checksum,
+ int recursion_depth,
+ GHashTable *inout_reachable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ int n, i;
+ gs_unref_variant GVariant *key = NULL;
+ gs_unref_variant GVariant *tree = NULL;
+ gs_unref_variant GVariant *files_variant = NULL;
+ gs_unref_variant GVariant *dirs_variant = NULL;
+ gs_unref_variant GVariant *csum_v = NULL;
+ gs_unref_variant GVariant *content_csum_v = NULL;
+ gs_unref_variant GVariant *metadata_csum_v = NULL;
+ gs_free char *tmp_checksum = NULL;
+
+ if (recursion_depth > OSTREE_MAX_RECURSION)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Maximum recursion limit reached during traversal");
+ goto out;
+ }
+
+ if (!ostree_repo_load_variant_if_exists (repo, OSTREE_OBJECT_TYPE_DIR_TREE, dirtree_checksum, &tree, error))
+ goto out;
+
+ if (!tree)
+ return TRUE;
+
+ key = ostree_object_name_serialize (dirtree_checksum, OSTREE_OBJECT_TYPE_DIR_TREE);
+ if (!g_hash_table_lookup (inout_reachable, key))
+ {
+ g_hash_table_insert (inout_reachable, key, key);
+ key = NULL;
+
+ /* PARSE OSTREE_SERIALIZED_TREE_VARIANT */
+ files_variant = g_variant_get_child_value (tree, 0);
+ n = g_variant_n_children (files_variant);
+ for (i = 0; i < n; i++)
+ {
+ const char *filename;
+
+ g_clear_pointer (&csum_v, (GDestroyNotify) g_variant_unref);
+ g_variant_get_child (files_variant, i, "(&s@ay)", &filename, &csum_v);
+ g_free (tmp_checksum);
+ tmp_checksum = ostree_checksum_from_bytes_v (csum_v);
+ key = ostree_object_name_serialize (tmp_checksum, OSTREE_OBJECT_TYPE_FILE);
+ g_hash_table_replace (inout_reachable, key, key);
+ key = NULL;
+ }
+
+ dirs_variant = g_variant_get_child_value (tree, 1);
+ n = g_variant_n_children (dirs_variant);
+ for (i = 0; i < n; i++)
+ {
+ const char *dirname;
+
+ g_clear_pointer (&content_csum_v, (GDestroyNotify) g_variant_unref);
+ g_clear_pointer (&metadata_csum_v, (GDestroyNotify) g_variant_unref);
+ g_variant_get_child (dirs_variant, i, "(&s@ay@ay)",
+ &dirname, &content_csum_v, &metadata_csum_v);
+
+ g_free (tmp_checksum);
+ tmp_checksum = ostree_checksum_from_bytes_v (content_csum_v);
+ if (!traverse_dirtree_internal (repo, tmp_checksum, recursion_depth + 1,
+ inout_reachable, cancellable, error))
+ goto out;
+
+ g_free (tmp_checksum);
+ tmp_checksum = ostree_checksum_from_bytes_v (metadata_csum_v);
+ key = ostree_object_name_serialize (tmp_checksum, OSTREE_OBJECT_TYPE_DIR_META);
+ g_hash_table_replace (inout_reachable, key, key);
+ key = NULL;
+ }
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+gboolean
+ostree_repo_traverse_dirtree (OstreeRepo *repo,
+ const char *dirtree_checksum,
+ GHashTable *inout_reachable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return traverse_dirtree_internal (repo, dirtree_checksum, 0,
+ inout_reachable, cancellable, error);
+}
+
+/**
+ * ostree_traverse_commit:
+ *
+ * Add to @inout_reachable all objects reachable from
+ * @commit_checksum, traversing @maxdepth parent commits.
+ */
+gboolean
+ostree_repo_traverse_commit (OstreeRepo *repo,
+ const char *commit_checksum,
+ int maxdepth,
+ GHashTable *inout_reachable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_free char*tmp_checksum = NULL;
+
+ while (TRUE)
+ {
+ gboolean recurse = FALSE;
+ gs_unref_variant GVariant *parent_csum_bytes = NULL;
+ gs_unref_variant GVariant *meta_csum_bytes = NULL;
+ gs_unref_variant GVariant *content_csum_bytes = NULL;
+ gs_unref_variant GVariant *key = NULL;
+ gs_unref_variant GVariant *commit = NULL;
+
+ key = ostree_object_name_serialize (commit_checksum, OSTREE_OBJECT_TYPE_COMMIT);
+
+ if (g_hash_table_contains (inout_reachable, key))
+ break;
+
+ /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */
+ if (!ostree_repo_load_variant_if_exists (repo, OSTREE_OBJECT_TYPE_COMMIT, commit_checksum, &commit, error))
+ goto out;
+
+ /* Just return if the parent isn't found; we do expect most
+ * people to have partial repositories.
+ */
+ if (!commit)
+ break;
+
+ g_hash_table_add (inout_reachable, key);
+ key = NULL;
+
+ g_variant_get_child (commit, 7, "@ay", &meta_csum_bytes);
+ g_free (tmp_checksum);
+ if (G_UNLIKELY (g_variant_n_children (meta_csum_bytes) == 0))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Corrupted commit '%s'; invalid tree metadata",
+ commit_checksum);
+ goto out;
+ }
+
+ tmp_checksum = ostree_checksum_from_bytes_v (meta_csum_bytes);
+ key = ostree_object_name_serialize (tmp_checksum, OSTREE_OBJECT_TYPE_DIR_META);
+ g_hash_table_replace (inout_reachable, key, key);
+ key = NULL;
+
+ g_variant_get_child (commit, 6, "@ay", &content_csum_bytes);
+ g_free (tmp_checksum);
+ if (G_UNLIKELY (g_variant_n_children (content_csum_bytes) == 0))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Corrupted commit '%s'; invalid tree content",
+ commit_checksum);
+ goto out;
+ }
+
+ tmp_checksum = ostree_checksum_from_bytes_v (content_csum_bytes);
+ if (!ostree_repo_traverse_dirtree (repo, tmp_checksum, inout_reachable, cancellable, error))
+ goto out;
+
+ if (maxdepth == -1 || maxdepth > 0)
+ {
+ g_variant_get_child (commit, 1, "@ay", &parent_csum_bytes);
+
+ if (g_variant_n_children (parent_csum_bytes) > 0)
+ {
+ g_free (tmp_checksum);
+ tmp_checksum = ostree_checksum_from_bytes_v (parent_csum_bytes);
+ commit_checksum = tmp_checksum;
+ if (maxdepth > 0)
+ maxdepth -= 1;
+ recurse = TRUE;
+ }
+ }
+ if (!recurse)
+ break;
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+