diff options
author | Colin Walters <walters@verbum.org> | 2013-07-09 19:59:39 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2013-07-09 19:59:39 -0400 |
commit | 2aa0251b1b3dfc1bf06840c8e1fa35e59534c9e2 (patch) | |
tree | 4d842198a8546711e422d0929bb521a188b4e028 /src/libostree/ostree-repo-traverse.c | |
parent | cb6b69616c7e452599b9e49edf73fcd893fb887e (diff) | |
download | ostree-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.c | 227 |
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; +} + |