Blame src/libostree/ostree-repo-traverse.c

rpm-build 0fba15
/*
rpm-build 0fba15
 * Copyright (C) 2011 Colin Walters <walters@verbum.org>
rpm-build 0fba15
 *
rpm-build 0fba15
 * SPDX-License-Identifier: LGPL-2.0+
rpm-build 0fba15
 *
rpm-build 0fba15
 * This library is free software; you can redistribute it and/or
rpm-build 0fba15
 * modify it under the terms of the GNU Lesser General Public
rpm-build 0fba15
 * License as published by the Free Software Foundation; either
rpm-build 0fba15
 * version 2 of the License, or (at your option) any later version.
rpm-build 0fba15
 *
rpm-build 0fba15
 * This library is distributed in the hope that it will be useful,
rpm-build 0fba15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rpm-build 0fba15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
rpm-build 0fba15
 * Lesser General Public License for more details.
rpm-build 0fba15
 *
rpm-build 0fba15
 * You should have received a copy of the GNU Lesser General Public
rpm-build 0fba15
 * License along with this library; if not, write to the
rpm-build 0fba15
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
rpm-build 0fba15
 * Boston, MA 02111-1307, USA.
rpm-build 0fba15
 *
rpm-build 0fba15
 * Author: Colin Walters <walters@verbum.org>
rpm-build 0fba15
 */
rpm-build 0fba15
rpm-build 0fba15
#include "config.h"
rpm-build 0fba15
rpm-build 0fba15
#include "libglnx.h"
rpm-build 0fba15
#include "ostree.h"
rpm-build 0fba15
#include "otutil.h"
rpm-build 0fba15
rpm-build 0fba15
struct _OstreeRepoRealCommitTraverseIter {
rpm-build 0fba15
  gboolean initialized;
rpm-build 0fba15
  OstreeRepo *repo;
rpm-build 0fba15
  GVariant *commit;
rpm-build 0fba15
  GVariant *current_dir;
rpm-build 0fba15
  const char *name;
rpm-build 0fba15
  OstreeRepoCommitIterResult state;
rpm-build 0fba15
  guint idx;
rpm-build 0fba15
  char checksum_content[OSTREE_SHA256_STRING_LEN+1];
rpm-build 0fba15
  char checksum_meta[OSTREE_SHA256_STRING_LEN+1];
rpm-build 0fba15
};
rpm-build 0fba15
rpm-build 0fba15
/**
rpm-build 0fba15
 * ostree_repo_commit_traverse_iter_init_commit:
rpm-build 0fba15
 * @iter: An iter
rpm-build 0fba15
 * @repo: A repo
rpm-build 0fba15
 * @commit: Variant of type %OSTREE_OBJECT_TYPE_COMMIT
rpm-build 0fba15
 * @flags: Flags
rpm-build 0fba15
 * @error: Error
rpm-build 0fba15
 *
rpm-build 0fba15
 * Initialize (in place) an iterator over the root of a commit object.
rpm-build 0fba15
 */
rpm-build 0fba15
gboolean
rpm-build 0fba15
ostree_repo_commit_traverse_iter_init_commit (OstreeRepoCommitTraverseIter   *iter,
rpm-build 0fba15
                                              OstreeRepo                     *repo,
rpm-build 0fba15
                                              GVariant                       *commit,
rpm-build 0fba15
                                              OstreeRepoCommitTraverseFlags   flags,
rpm-build 0fba15
                                              GError                        **error)
rpm-build 0fba15
{
rpm-build 0fba15
  struct _OstreeRepoRealCommitTraverseIter *real =
rpm-build 0fba15
    (struct _OstreeRepoRealCommitTraverseIter*)iter;
rpm-build 0fba15
rpm-build 0fba15
  memset (real, 0, sizeof (*real));
rpm-build 0fba15
  real->initialized = TRUE;
rpm-build 0fba15
  real->repo = g_object_ref (repo);
rpm-build 0fba15
  real->commit = g_variant_ref (commit);
rpm-build 0fba15
  real->current_dir = NULL;
rpm-build 0fba15
  real->idx = 0;
rpm-build 0fba15
rpm-build 0fba15
  g_autoptr(GVariant) content_csum_bytes = NULL;
rpm-build 0fba15
  g_variant_get_child (commit, 6, "@ay", &content_csum_bytes);
rpm-build 0fba15
  const guchar *csum = ostree_checksum_bytes_peek_validate (content_csum_bytes, error);
rpm-build 0fba15
  if (!csum)
rpm-build 0fba15
    return FALSE;
rpm-build 0fba15
  ostree_checksum_inplace_from_bytes (csum, real->checksum_content);
rpm-build 0fba15
rpm-build 0fba15
  g_autoptr(GVariant) meta_csum_bytes = NULL;
rpm-build 0fba15
  g_variant_get_child (commit, 7, "@ay", &meta_csum_bytes);
rpm-build 0fba15
  csum = ostree_checksum_bytes_peek_validate (meta_csum_bytes, error);
rpm-build 0fba15
  if (!csum)
rpm-build 0fba15
    return FALSE;
rpm-build 0fba15
  ostree_checksum_inplace_from_bytes (csum, real->checksum_meta);
rpm-build 0fba15
rpm-build 0fba15
  return TRUE;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/**
rpm-build 0fba15
 * ostree_repo_commit_traverse_iter_init_dirtree:
rpm-build 0fba15
 * @iter: An iter
rpm-build 0fba15
 * @repo: A repo
rpm-build 0fba15
 * @dirtree: Variant of type %OSTREE_OBJECT_TYPE_DIR_TREE
rpm-build 0fba15
 * @flags: Flags
rpm-build 0fba15
 * @error: Error
rpm-build 0fba15
 *
rpm-build 0fba15
 * Initialize (in place) an iterator over a directory tree.
rpm-build 0fba15
 */
rpm-build 0fba15
gboolean
rpm-build 0fba15
ostree_repo_commit_traverse_iter_init_dirtree (OstreeRepoCommitTraverseIter   *iter,
rpm-build 0fba15
                                               OstreeRepo                     *repo,
rpm-build 0fba15
                                               GVariant                       *dirtree,
rpm-build 0fba15
                                               OstreeRepoCommitTraverseFlags   flags,
rpm-build 0fba15
                                               GError                        **error)
rpm-build 0fba15
{
rpm-build 0fba15
  struct _OstreeRepoRealCommitTraverseIter *real =
rpm-build 0fba15
    (struct _OstreeRepoRealCommitTraverseIter*)iter;
rpm-build 0fba15
rpm-build 0fba15
  memset (real, 0, sizeof (*real));
rpm-build 0fba15
  real->initialized = TRUE;
rpm-build 0fba15
  real->repo = g_object_ref (repo);
rpm-build 0fba15
  real->current_dir = g_variant_ref (dirtree);
rpm-build 0fba15
  real->idx = 0;
rpm-build 0fba15
rpm-build 0fba15
  return TRUE;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/**
rpm-build 0fba15
 * ostree_repo_commit_traverse_iter_next:
rpm-build 0fba15
 * @iter: An iter
rpm-build 0fba15
 * @cancellable: Cancellable
rpm-build 0fba15
 * @error: Error
rpm-build 0fba15
 *
rpm-build 0fba15
 * Step the interator to the next item.  Files will be returned first,
rpm-build 0fba15
 * then subdirectories.  Call this in a loop; upon encountering
rpm-build 0fba15
 * %OSTREE_REPO_COMMIT_ITER_RESULT_END, there will be no more files or
rpm-build 0fba15
 * directories.  If %OSTREE_REPO_COMMIT_ITER_RESULT_DIR is returned,
rpm-build 0fba15
 * then call ostree_repo_commit_traverse_iter_get_dir() to retrieve
rpm-build 0fba15
 * data for that directory.  Similarly, if
rpm-build 0fba15
 * %OSTREE_REPO_COMMIT_ITER_RESULT_FILE is returned, call
rpm-build 0fba15
 * ostree_repo_commit_traverse_iter_get_file().
rpm-build 0fba15
 * 
rpm-build 0fba15
 * If %OSTREE_REPO_COMMIT_ITER_RESULT_ERROR is returned, it is a
rpm-build 0fba15
 * program error to call any further API on @iter except for
rpm-build 0fba15
 * ostree_repo_commit_traverse_iter_clear().
rpm-build 0fba15
 */
rpm-build 0fba15
OstreeRepoCommitIterResult
rpm-build 0fba15
ostree_repo_commit_traverse_iter_next (OstreeRepoCommitTraverseIter *iter,
rpm-build 0fba15
                                       GCancellable                 *cancellable,
rpm-build 0fba15
                                       GError                      **error)
rpm-build 0fba15
{
rpm-build 0fba15
  struct _OstreeRepoRealCommitTraverseIter *real =
rpm-build 0fba15
    (struct _OstreeRepoRealCommitTraverseIter*)iter;
rpm-build 0fba15
  OstreeRepoCommitIterResult res = OSTREE_REPO_COMMIT_ITER_RESULT_ERROR;
rpm-build 0fba15
rpm-build 0fba15
  if (!real->current_dir)
rpm-build 0fba15
    {
rpm-build 0fba15
      if (!ostree_repo_load_variant (real->repo, OSTREE_OBJECT_TYPE_DIR_TREE,
rpm-build 0fba15
                                     real->checksum_content,
rpm-build 0fba15
                                     &real->current_dir,
rpm-build 0fba15
                                     error))
rpm-build 0fba15
        goto out;
rpm-build 0fba15
      res = OSTREE_REPO_COMMIT_ITER_RESULT_DIR;
rpm-build 0fba15
    }
rpm-build 0fba15
  else
rpm-build 0fba15
    {
rpm-build 0fba15
      guint nfiles;
rpm-build 0fba15
      guint ndirs;
rpm-build 0fba15
      guint idx;
rpm-build 0fba15
      const guchar *csum;
rpm-build 0fba15
      g_autoptr(GVariant) content_csum_v = NULL;
rpm-build 0fba15
      g_autoptr(GVariant) meta_csum_v = NULL;
rpm-build 0fba15
      g_autoptr(GVariant) files_variant = NULL;
rpm-build 0fba15
      g_autoptr(GVariant) dirs_variant = NULL;
rpm-build 0fba15
rpm-build 0fba15
      files_variant = g_variant_get_child_value (real->current_dir, 0);
rpm-build 0fba15
      dirs_variant = g_variant_get_child_value (real->current_dir, 1);
rpm-build 0fba15
rpm-build 0fba15
      nfiles = g_variant_n_children (files_variant);
rpm-build 0fba15
      ndirs = g_variant_n_children (dirs_variant);
rpm-build 0fba15
      if (real->idx < nfiles)
rpm-build 0fba15
        {
rpm-build 0fba15
          idx = real->idx;
rpm-build 0fba15
          g_variant_get_child (files_variant, idx, "(&s@ay)",
rpm-build 0fba15
                               &real->name,
rpm-build 0fba15
                               &content_csum_v);
rpm-build 0fba15
rpm-build 0fba15
          csum = ostree_checksum_bytes_peek_validate (content_csum_v, error);
rpm-build 0fba15
          if (!csum)
rpm-build 0fba15
            goto out;
rpm-build 0fba15
          ostree_checksum_inplace_from_bytes (csum, real->checksum_content);
rpm-build 0fba15
rpm-build 0fba15
          res = OSTREE_REPO_COMMIT_ITER_RESULT_FILE;
rpm-build 0fba15
rpm-build 0fba15
          real->idx++;
rpm-build 0fba15
        }
rpm-build 0fba15
      else if (real->idx < nfiles + ndirs)
rpm-build 0fba15
        {
rpm-build 0fba15
          idx = real->idx - nfiles;
rpm-build 0fba15
rpm-build 0fba15
          g_variant_get_child (dirs_variant, idx, "(&s@ay@ay)",
rpm-build 0fba15
                               &real->name, &content_csum_v, &meta_csum_v);
rpm-build 0fba15
rpm-build 0fba15
          csum = ostree_checksum_bytes_peek_validate (content_csum_v, error);
rpm-build 0fba15
          if (!csum)
rpm-build 0fba15
            goto out;
rpm-build 0fba15
          ostree_checksum_inplace_from_bytes (csum, real->checksum_content);
rpm-build 0fba15
rpm-build 0fba15
          csum = ostree_checksum_bytes_peek_validate (meta_csum_v, error);
rpm-build 0fba15
          if (!csum)
rpm-build 0fba15
            goto out;
rpm-build 0fba15
          ostree_checksum_inplace_from_bytes (csum, real->checksum_meta);
rpm-build 0fba15
          
rpm-build 0fba15
          res = OSTREE_REPO_COMMIT_ITER_RESULT_DIR;
rpm-build 0fba15
rpm-build 0fba15
          real->idx++;
rpm-build 0fba15
        }
rpm-build 0fba15
      else
rpm-build 0fba15
        res = OSTREE_REPO_COMMIT_ITER_RESULT_END;
rpm-build 0fba15
    }
rpm-build 0fba15
  
rpm-build 0fba15
  real->state = res;
rpm-build 0fba15
 out:
rpm-build 0fba15
  return res;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/**
rpm-build 0fba15
 * ostree_repo_commit_traverse_iter_get_file:
rpm-build 0fba15
 * @iter: An iter
rpm-build 0fba15
 * @out_name: (out) (transfer none): Name of current file
rpm-build 0fba15
 * @out_checksum: (out) (transfer none): Checksum of current file
rpm-build 0fba15
 *
rpm-build 0fba15
 * Return information on the current file.  This function may only be
rpm-build 0fba15
 * called if %OSTREE_REPO_COMMIT_ITER_RESULT_FILE was returned from
rpm-build 0fba15
 * ostree_repo_commit_traverse_iter_next().
rpm-build 0fba15
 */
rpm-build 0fba15
void
rpm-build 0fba15
ostree_repo_commit_traverse_iter_get_file (OstreeRepoCommitTraverseIter *iter,
rpm-build 0fba15
                                           char                        **out_name,
rpm-build 0fba15
                                           char                        **out_checksum)
rpm-build 0fba15
{
rpm-build 0fba15
  struct _OstreeRepoRealCommitTraverseIter *real =
rpm-build 0fba15
    (struct _OstreeRepoRealCommitTraverseIter*)iter;
rpm-build 0fba15
  *out_name = (char*)real->name;
rpm-build 0fba15
  *out_checksum = (char*)real->checksum_content;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/**
rpm-build 0fba15
 * ostree_repo_commit_traverse_iter_get_dir:
rpm-build 0fba15
 * @iter: An iter
rpm-build 0fba15
 * @out_name: (out) (transfer none): Name of current dir
rpm-build 0fba15
 * @out_content_checksum: (out) (transfer none): Checksum of current content
rpm-build 0fba15
 * @out_meta_checksum: (out) (transfer none): Checksum of current metadata
rpm-build 0fba15
 *
rpm-build 0fba15
 * Return information on the current directory.  This function may
rpm-build 0fba15
 * only be called if %OSTREE_REPO_COMMIT_ITER_RESULT_DIR was returned
rpm-build 0fba15
 * from ostree_repo_commit_traverse_iter_next().
rpm-build 0fba15
 */
rpm-build 0fba15
void
rpm-build 0fba15
ostree_repo_commit_traverse_iter_get_dir (OstreeRepoCommitTraverseIter *iter,
rpm-build 0fba15
                                          char                        **out_name,
rpm-build 0fba15
                                          char                        **out_content_checksum,
rpm-build 0fba15
                                          char                        **out_meta_checksum)
rpm-build 0fba15
{
rpm-build 0fba15
  struct _OstreeRepoRealCommitTraverseIter *real =
rpm-build 0fba15
    (struct _OstreeRepoRealCommitTraverseIter*)iter;
rpm-build 0fba15
  *out_name = (char*)real->name;
rpm-build 0fba15
  *out_content_checksum = (char*)real->checksum_content;
rpm-build 0fba15
  *out_meta_checksum = (char*)real->checksum_meta;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
void
rpm-build 0fba15
ostree_repo_commit_traverse_iter_clear (OstreeRepoCommitTraverseIter *iter)
rpm-build 0fba15
{
rpm-build 0fba15
  struct _OstreeRepoRealCommitTraverseIter *real =
rpm-build 0fba15
    (struct _OstreeRepoRealCommitTraverseIter*)iter;
rpm-build 0fba15
  g_clear_object (&real->repo);
rpm-build 0fba15
  g_clear_pointer (&real->commit, g_variant_unref);
rpm-build 0fba15
  g_clear_pointer (&real->current_dir, g_variant_unref);
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
void
rpm-build 0fba15
ostree_repo_commit_traverse_iter_cleanup (void *p)
rpm-build 0fba15
{
rpm-build 0fba15
  OstreeRepoCommitTraverseIter *iter = p;
rpm-build 0fba15
  struct _OstreeRepoRealCommitTraverseIter *real =
rpm-build 0fba15
    (struct _OstreeRepoRealCommitTraverseIter*)iter;
rpm-build 0fba15
  if (real->initialized)
rpm-build 0fba15
    {
rpm-build 0fba15
      ostree_repo_commit_traverse_iter_clear (iter);
rpm-build 0fba15
      real->initialized = FALSE;
rpm-build 0fba15
    }
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/**
rpm-build 0fba15
 * ostree_repo_traverse_new_reachable:
rpm-build 0fba15
 *
rpm-build 0fba15
 * This hash table is a set of #GVariant which can be accessed via
rpm-build 0fba15
 * ostree_object_name_deserialize().
rpm-build 0fba15
 *
rpm-build 0fba15
 * Returns: (transfer container) (element-type GVariant GVariant): A new hash table
rpm-build 0fba15
 */
rpm-build 0fba15
GHashTable *
rpm-build 0fba15
ostree_repo_traverse_new_reachable (void)
rpm-build 0fba15
{
rpm-build 0fba15
  return g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
rpm-build 0fba15
                                NULL, (GDestroyNotify)g_variant_unref);
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/**
rpm-build 0fba15
 * ostree_repo_traverse_new_parents:
rpm-build 0fba15
 *
rpm-build 0fba15
 * This hash table is a mapping from #GVariant which can be accessed
rpm-build 0fba15
 * via ostree_object_name_deserialize() to a #GVariant containing either
rpm-build 0fba15
 * a similar #GVariant or and array of them, listing the parents of the key.
rpm-build 0fba15
 *
rpm-build 0fba15
 * Returns: (transfer container) (element-type GVariant GVariant): A new hash table
rpm-build 0fba15
 *
rpm-build 0fba15
 * Since: 2018.5
rpm-build 0fba15
 */
rpm-build 0fba15
GHashTable *
rpm-build 0fba15
ostree_repo_traverse_new_parents (void)
rpm-build 0fba15
{
rpm-build 0fba15
  return g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
rpm-build 0fba15
                                (GDestroyNotify)g_variant_unref, (GDestroyNotify)g_variant_unref);
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static void
rpm-build 0fba15
parents_get_commits (GHashTable *parents_ht, GVariant *object, GHashTable *res)
rpm-build 0fba15
{
rpm-build 0fba15
  const char *checksum;
rpm-build 0fba15
  OstreeObjectType type;
rpm-build 0fba15
rpm-build 0fba15
  if (object == NULL)
rpm-build 0fba15
    return;
rpm-build 0fba15
rpm-build 0fba15
  ostree_object_name_deserialize (object, &checksum, &type);
rpm-build 0fba15
  if (type == OSTREE_OBJECT_TYPE_COMMIT)
rpm-build 0fba15
    g_hash_table_add (res, g_strdup (checksum));
rpm-build 0fba15
  else
rpm-build 0fba15
    {
rpm-build 0fba15
      GVariant *parents = g_hash_table_lookup (parents_ht, object);
rpm-build 0fba15
rpm-build 0fba15
      if (parents == NULL)
rpm-build 0fba15
        g_debug ("Unexpected NULL parent");
rpm-build 0fba15
      else if (g_variant_is_of_type (parents, G_VARIANT_TYPE_ARRAY))
rpm-build 0fba15
        {
rpm-build 0fba15
          gsize i, len = g_variant_n_children (parents);
rpm-build 0fba15
rpm-build 0fba15
          for (i = 0; i < len; i++)
rpm-build 0fba15
            {
rpm-build 0fba15
              g_autoptr(GVariant) parent = g_variant_get_child_value (parents, i);
rpm-build 0fba15
              parents_get_commits (parents_ht, parent, res);
rpm-build 0fba15
            }
rpm-build 0fba15
        }
rpm-build 0fba15
      else
rpm-build 0fba15
        parents_get_commits (parents_ht, parents, res);
rpm-build 0fba15
    }
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/**
rpm-build 0fba15
 * ostree_repo_traverse_parents_get_commits:
rpm-build 0fba15
 *
rpm-build 0fba15
 * Gets all the commits that a certain object belongs to, as recorded
rpm-build 0fba15
 * by a parents table gotten from ostree_repo_traverse_commit_union_with_parents.
rpm-build 0fba15
 *
rpm-build 0fba15
 * Returns: (transfer full) (array zero-terminated=1): An array of checksums for
rpm-build 0fba15
 * the commits the key belongs to.
rpm-build 0fba15
 *
rpm-build 0fba15
 * Since: 2018.5
rpm-build 0fba15
 */
rpm-build 0fba15
char **
rpm-build 0fba15
ostree_repo_traverse_parents_get_commits (GHashTable *parents, GVariant *object)
rpm-build 0fba15
{
rpm-build 0fba15
  g_autoptr(GHashTable) res = g_hash_table_new (g_str_hash, g_str_equal);
rpm-build 0fba15
rpm-build 0fba15
  parents_get_commits (parents, object, res);
rpm-build 0fba15
rpm-build 0fba15
  return (char **)g_hash_table_get_keys_as_array (res, NULL);
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static gboolean
rpm-build 0fba15
traverse_dirtree (OstreeRepo           *repo,
rpm-build 0fba15
                  const char           *checksum,
rpm-build 0fba15
                  GVariant             *parent_key,
rpm-build 0fba15
                  GHashTable           *inout_reachable,
rpm-build 0fba15
                  GHashTable           *inout_parents,
rpm-build 0fba15
                  gboolean              ignore_missing_dirs,
rpm-build 0fba15
                  GCancellable         *cancellable,
rpm-build 0fba15
                  GError              **error);
rpm-build 0fba15
rpm-build 0fba15
static void
rpm-build 0fba15
add_parent_ref (GHashTable  *inout_parents,
rpm-build 0fba15
                GVariant    *key,
rpm-build 0fba15
                GVariant    *parent_key)
rpm-build 0fba15
{
rpm-build 0fba15
  GVariant *old_parents;
rpm-build 0fba15
rpm-build 0fba15
  if (inout_parents == NULL)
rpm-build 0fba15
    return;
rpm-build 0fba15
rpm-build 0fba15
  old_parents = g_hash_table_lookup (inout_parents, key);
rpm-build 0fba15
  if (old_parents == NULL)
rpm-build 0fba15
    {
rpm-build 0fba15
      /* For the common case of a single pointer we skip using an array to save memory. */
rpm-build 0fba15
      g_hash_table_insert (inout_parents, g_variant_ref (key), g_variant_ref (parent_key));
rpm-build 0fba15
    }
rpm-build 0fba15
  else
rpm-build 0fba15
    {
rpm-build 0fba15
      g_autofree GVariant **new_parents = NULL;
rpm-build 0fba15
      gsize i, len = 0;
rpm-build 0fba15
rpm-build 0fba15
      if (g_variant_is_of_type (old_parents, G_VARIANT_TYPE_ARRAY))
rpm-build 0fba15
        {
rpm-build 0fba15
          gsize old_parents_len = g_variant_n_children (old_parents);
rpm-build 0fba15
          new_parents = g_new (GVariant *,  old_parents_len + 1);
rpm-build 0fba15
          for (i = 0; i < old_parents_len ; i++)
rpm-build 0fba15
            {
rpm-build 0fba15
              g_autoptr(GVariant) old_parent = g_variant_get_child_value (old_parents, i);
rpm-build 0fba15
              if (!g_variant_equal (old_parent, parent_key))
rpm-build 0fba15
                new_parents[len++] = g_steal_pointer (&old_parent);
rpm-build 0fba15
            }
rpm-build 0fba15
        }
rpm-build 0fba15
      else
rpm-build 0fba15
        {
rpm-build 0fba15
          new_parents = g_new (GVariant *, 2);
rpm-build 0fba15
          if (!g_variant_equal (old_parents, parent_key))
rpm-build 0fba15
            new_parents[len++] = g_variant_ref (old_parents);
rpm-build 0fba15
        }
rpm-build 0fba15
      new_parents[len++] = g_variant_ref (parent_key);
rpm-build 0fba15
      g_hash_table_insert (inout_parents, g_variant_ref (key),
rpm-build 0fba15
                           g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(su)"), new_parents , len)));
rpm-build 0fba15
      for (i = 0; i < len; i++)
rpm-build 0fba15
        g_variant_unref (new_parents[i]);
rpm-build 0fba15
    }
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
rpm-build 0fba15
static gboolean
rpm-build 0fba15
traverse_iter (OstreeRepo                          *repo,
rpm-build 0fba15
               OstreeRepoCommitTraverseIter        *iter,
rpm-build 0fba15
               GVariant                            *parent_key,
rpm-build 0fba15
               GHashTable                          *inout_reachable,
rpm-build 0fba15
               GHashTable                          *inout_parents,
rpm-build 0fba15
               gboolean                             ignore_missing_dirs,
rpm-build 0fba15
               GCancellable                        *cancellable,
rpm-build 0fba15
               GError                             **error)
rpm-build 0fba15
{
rpm-build 0fba15
  while (TRUE)
rpm-build 0fba15
    {
rpm-build 0fba15
      g_autoptr(GVariant) key = NULL;
rpm-build 0fba15
      g_autoptr(GError) local_error = NULL;
rpm-build 0fba15
      OstreeRepoCommitIterResult iterres =
rpm-build 0fba15
        ostree_repo_commit_traverse_iter_next (iter, cancellable, &local_error);
rpm-build 0fba15
rpm-build 0fba15
      if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_ERROR)
rpm-build 0fba15
        {
rpm-build 0fba15
          /* There is only one kind of not-found error, which is
rpm-build 0fba15
             failing to load the dirmeta itself, if so, we ignore that
rpm-build 0fba15
             (and the whole subtree) if told to. */
rpm-build 0fba15
          if (ignore_missing_dirs &&
rpm-build 0fba15
              g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
rpm-build 0fba15
            {
rpm-build 0fba15
              g_debug ("Ignoring not-found dirmeta");
rpm-build 0fba15
              return TRUE;  /* Note early return */
rpm-build 0fba15
            }
rpm-build 0fba15
rpm-build 0fba15
          g_propagate_error (error, g_steal_pointer (&local_error));
rpm-build 0fba15
          return FALSE;
rpm-build 0fba15
        }
rpm-build 0fba15
      else if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_END)
rpm-build 0fba15
        break;
rpm-build 0fba15
      else if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_FILE)
rpm-build 0fba15
        {
rpm-build 0fba15
          char *name;
rpm-build 0fba15
          char *checksum;
rpm-build 0fba15
rpm-build 0fba15
          ostree_repo_commit_traverse_iter_get_file (iter, &name, &checksum);
rpm-build 0fba15
rpm-build 0fba15
          g_debug ("Found file object %s", checksum);
rpm-build 0fba15
          key = g_variant_ref_sink (ostree_object_name_serialize (checksum, OSTREE_OBJECT_TYPE_FILE));
rpm-build 0fba15
          add_parent_ref (inout_parents, key, parent_key);
rpm-build 0fba15
          g_hash_table_add (inout_reachable, g_steal_pointer (&key));
rpm-build 0fba15
        }
rpm-build 0fba15
      else if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_DIR)
rpm-build 0fba15
        {
rpm-build 0fba15
          char *name;
rpm-build 0fba15
          char *content_checksum;
rpm-build 0fba15
          char *meta_checksum;
rpm-build 0fba15
rpm-build 0fba15
          ostree_repo_commit_traverse_iter_get_dir (iter, &name, &content_checksum,
rpm-build 0fba15
                                                    &meta_checksum);
rpm-build 0fba15
rpm-build 0fba15
          g_debug ("Found dirtree object %s", content_checksum);
rpm-build 0fba15
          g_debug ("Found dirmeta object %s", meta_checksum);
rpm-build 0fba15
          key = g_variant_ref_sink (ostree_object_name_serialize (meta_checksum, OSTREE_OBJECT_TYPE_DIR_META));
rpm-build 0fba15
          add_parent_ref (inout_parents, key, parent_key);
rpm-build 0fba15
          g_hash_table_add (inout_reachable, g_steal_pointer (&key));
rpm-build 0fba15
rpm-build 0fba15
          key = g_variant_ref_sink (ostree_object_name_serialize (content_checksum, OSTREE_OBJECT_TYPE_DIR_TREE));
rpm-build 0fba15
          add_parent_ref (inout_parents, key, parent_key);
rpm-build 0fba15
          if (!g_hash_table_lookup (inout_reachable, key))
rpm-build 0fba15
            {
rpm-build 0fba15
              if (!traverse_dirtree (repo, content_checksum, key, inout_reachable, inout_parents,
rpm-build 0fba15
                                     ignore_missing_dirs, cancellable, error))
rpm-build 0fba15
                return FALSE;
rpm-build 0fba15
rpm-build 0fba15
              g_hash_table_add (inout_reachable, g_steal_pointer (&key));
rpm-build 0fba15
            }
rpm-build 0fba15
        }
rpm-build 0fba15
      else
rpm-build 0fba15
        g_assert_not_reached ();
rpm-build 0fba15
    }
rpm-build 0fba15
rpm-build 0fba15
  return TRUE;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
static gboolean
rpm-build 0fba15
traverse_dirtree (OstreeRepo           *repo,
rpm-build 0fba15
                  const char           *checksum,
rpm-build 0fba15
                  GVariant             *parent_key,
rpm-build 0fba15
                  GHashTable           *inout_reachable,
rpm-build 0fba15
                  GHashTable           *inout_parents,
rpm-build 0fba15
                  gboolean              ignore_missing_dirs,
rpm-build 0fba15
                  GCancellable         *cancellable,
rpm-build 0fba15
                  GError              **error)
rpm-build 0fba15
{
rpm-build 0fba15
  g_autoptr(GError) local_error = NULL;
rpm-build 0fba15
rpm-build 0fba15
  g_autoptr(GVariant) dirtree = NULL;
rpm-build 0fba15
  if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_DIR_TREE, checksum,
rpm-build 0fba15
                                 &dirtree, &local_error))
rpm-build 0fba15
    {
rpm-build 0fba15
      if (ignore_missing_dirs &&
rpm-build 0fba15
          g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
rpm-build 0fba15
        {
rpm-build 0fba15
          g_debug ("Ignoring not-found dirmeta %s", checksum);
rpm-build 0fba15
          return TRUE; /* Early return */
rpm-build 0fba15
        }
rpm-build 0fba15
rpm-build 0fba15
      g_propagate_error (error, g_steal_pointer (&local_error));
rpm-build 0fba15
      return FALSE;
rpm-build 0fba15
    }
rpm-build 0fba15
rpm-build 0fba15
  g_debug ("Traversing dirtree %s", checksum);
rpm-build 0fba15
  ostree_cleanup_repo_commit_traverse_iter
rpm-build 0fba15
    OstreeRepoCommitTraverseIter iter = { 0, };
rpm-build 0fba15
  if (!ostree_repo_commit_traverse_iter_init_dirtree (&iter, repo, dirtree,
rpm-build 0fba15
                                                      OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE,
rpm-build 0fba15
                                                      error))
rpm-build 0fba15
    return FALSE;
rpm-build 0fba15
rpm-build 0fba15
  if (!traverse_iter (repo, &iter, parent_key, inout_reachable, inout_parents, ignore_missing_dirs, cancellable, error))
rpm-build 0fba15
    return FALSE;
rpm-build 0fba15
rpm-build 0fba15
  return TRUE;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/**
rpm-build 0fba15
 * ostree_repo_traverse_commit_union_with_parents: (skip)
rpm-build 0fba15
 * @repo: Repo
rpm-build 0fba15
 * @commit_checksum: ASCII SHA256 checksum
rpm-build 0fba15
 * @maxdepth: Traverse this many parent commits, -1 for unlimited
rpm-build 0fba15
 * @inout_reachable: Set of reachable objects
rpm-build 0fba15
 * @inout_parents: Map from object to parent object
rpm-build 0fba15
 * @cancellable: Cancellable
rpm-build 0fba15
 * @error: Error
rpm-build 0fba15
 *
rpm-build 0fba15
 * Update the set @inout_reachable containing all objects reachable
rpm-build 0fba15
 * from @commit_checksum, traversing @maxdepth parent commits.
rpm-build 0fba15
 *
rpm-build 0fba15
 * Additionally this constructs a mapping from each object to the parents
rpm-build 0fba15
 * of the object, which can be used to track which commits an object
rpm-build 0fba15
 * belongs to.
rpm-build 0fba15
 *
rpm-build 0fba15
 * Since: 2018.5
rpm-build 0fba15
 */
rpm-build 0fba15
gboolean
rpm-build 0fba15
ostree_repo_traverse_commit_union_with_parents (OstreeRepo      *repo,
rpm-build 0fba15
                                                const char      *commit_checksum,
rpm-build 0fba15
                                                int              maxdepth,
rpm-build 0fba15
                                                GHashTable      *inout_reachable,
rpm-build 0fba15
                                                GHashTable      *inout_parents,
rpm-build 0fba15
                                                GCancellable    *cancellable,
rpm-build 0fba15
                                                GError         **error)
rpm-build 0fba15
{
rpm-build 0fba15
  g_autofree char *tmp_checksum = NULL;
rpm-build 0fba15
rpm-build 0fba15
  while (TRUE)
rpm-build 0fba15
    {
rpm-build 0fba15
      g_autoptr(GVariant) key =
rpm-build 0fba15
        g_variant_ref_sink (ostree_object_name_serialize (commit_checksum, OSTREE_OBJECT_TYPE_COMMIT));
rpm-build 0fba15
rpm-build 0fba15
      if (g_hash_table_contains (inout_reachable, key))
rpm-build 0fba15
        break;
rpm-build 0fba15
rpm-build 0fba15
      g_autoptr(GVariant) commit = NULL;
rpm-build 0fba15
      if (!ostree_repo_load_variant_if_exists (repo, OSTREE_OBJECT_TYPE_COMMIT,
rpm-build 0fba15
                                               commit_checksum, &commit,
rpm-build 0fba15
                                               error))
rpm-build 0fba15
        return FALSE;
rpm-build 0fba15
rpm-build 0fba15
      /* Just return if the parent isn't found; we do expect most
rpm-build 0fba15
       * people to have partial repositories.
rpm-build 0fba15
       */
rpm-build 0fba15
      if (!commit)
rpm-build 0fba15
        break;
rpm-build 0fba15
rpm-build 0fba15
      /* See if the commit is partial, if so it's not an error to lack objects */
rpm-build 0fba15
      OstreeRepoCommitState commitstate;
rpm-build 0fba15
      if (!ostree_repo_load_commit (repo, commit_checksum, NULL, &commitstate,
rpm-build 0fba15
                                    error))
rpm-build 0fba15
        return FALSE;
rpm-build 0fba15
rpm-build 0fba15
      gboolean ignore_missing_dirs = FALSE;
rpm-build 0fba15
      if ((commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL) != 0)
rpm-build 0fba15
        ignore_missing_dirs = TRUE;
rpm-build 0fba15
rpm-build 0fba15
      g_hash_table_add (inout_reachable, g_variant_ref (key));
rpm-build 0fba15
rpm-build 0fba15
      g_debug ("Traversing commit %s", commit_checksum);
rpm-build 0fba15
      ostree_cleanup_repo_commit_traverse_iter
rpm-build 0fba15
        OstreeRepoCommitTraverseIter iter = { 0, };
rpm-build 0fba15
      if (!ostree_repo_commit_traverse_iter_init_commit (&iter, repo, commit,
rpm-build 0fba15
                                                         OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE,
rpm-build 0fba15
                                                         error))
rpm-build 0fba15
        return FALSE;
rpm-build 0fba15
rpm-build 0fba15
      if (!traverse_iter (repo, &iter, key, inout_reachable, inout_parents, ignore_missing_dirs, cancellable, error))
rpm-build 0fba15
        return FALSE;
rpm-build 0fba15
rpm-build 0fba15
      gboolean recurse = FALSE;
rpm-build 0fba15
      if (maxdepth == -1 || maxdepth > 0)
rpm-build 0fba15
        {
rpm-build 0fba15
          g_free (tmp_checksum);
rpm-build 0fba15
          tmp_checksum = ostree_commit_get_parent (commit);
rpm-build 0fba15
          if (tmp_checksum)
rpm-build 0fba15
            {
rpm-build 0fba15
              commit_checksum = tmp_checksum;
rpm-build 0fba15
              if (maxdepth > 0)
rpm-build 0fba15
                maxdepth -= 1;
rpm-build 0fba15
              recurse = TRUE;
rpm-build 0fba15
            }
rpm-build 0fba15
        }
rpm-build 0fba15
      if (!recurse)
rpm-build 0fba15
        break;
rpm-build 0fba15
    }
rpm-build 0fba15
rpm-build 0fba15
  return TRUE;
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/**
rpm-build 0fba15
 * ostree_repo_traverse_commit_union: (skip)
rpm-build 0fba15
 * @repo: Repo
rpm-build 0fba15
 * @commit_checksum: ASCII SHA256 checksum
rpm-build 0fba15
 * @maxdepth: Traverse this many parent commits, -1 for unlimited
rpm-build 0fba15
 * @inout_reachable: Set of reachable objects
rpm-build 0fba15
 * @cancellable: Cancellable
rpm-build 0fba15
 * @error: Error
rpm-build 0fba15
 *
rpm-build 0fba15
 * Update the set @inout_reachable containing all objects reachable
rpm-build 0fba15
 * from @commit_checksum, traversing @maxdepth parent commits.
rpm-build 0fba15
 */
rpm-build 0fba15
gboolean
rpm-build 0fba15
ostree_repo_traverse_commit_union (OstreeRepo      *repo,
rpm-build 0fba15
                                   const char      *commit_checksum,
rpm-build 0fba15
                                   int              maxdepth,
rpm-build 0fba15
                                   GHashTable      *inout_reachable,
rpm-build 0fba15
                                   GCancellable    *cancellable,
rpm-build 0fba15
                                   GError         **error)
rpm-build 0fba15
{
rpm-build 0fba15
  return
rpm-build 0fba15
    ostree_repo_traverse_commit_union_with_parents (repo, commit_checksum, maxdepth,
rpm-build 0fba15
                                                    inout_reachable, NULL,
rpm-build 0fba15
                                                    cancellable, error);
rpm-build 0fba15
}
rpm-build 0fba15
rpm-build 0fba15
/**
rpm-build 0fba15
 * ostree_repo_traverse_commit:
rpm-build 0fba15
 * @repo: Repo
rpm-build 0fba15
 * @commit_checksum: ASCII SHA256 checksum
rpm-build 0fba15
 * @maxdepth: Traverse this many parent commits, -1 for unlimited
rpm-build 0fba15
 * @out_reachable: (out) (transfer container) (element-type GVariant GVariant): Set of reachable objects
rpm-build 0fba15
 * @cancellable: Cancellable
rpm-build 0fba15
 * @error: Error
rpm-build 0fba15
 *
rpm-build 0fba15
 * Create a new set @out_reachable containing all objects reachable
rpm-build 0fba15
 * from @commit_checksum, traversing @maxdepth parent commits.
rpm-build 0fba15
 */
rpm-build 0fba15
gboolean
rpm-build 0fba15
ostree_repo_traverse_commit (OstreeRepo      *repo,
rpm-build 0fba15
                             const char      *commit_checksum,
rpm-build 0fba15
                             int              maxdepth,
rpm-build 0fba15
                             GHashTable     **out_reachable,
rpm-build 0fba15
                             GCancellable    *cancellable,
rpm-build 0fba15
                             GError         **error)
rpm-build 0fba15
{
rpm-build 0fba15
  g_autoptr(GHashTable) ret_reachable = ostree_repo_traverse_new_reachable ();
rpm-build 0fba15
  if (!ostree_repo_traverse_commit_union (repo, commit_checksum, maxdepth,
rpm-build 0fba15
                                          ret_reachable, cancellable, error))
rpm-build 0fba15
    return FALSE;
rpm-build 0fba15
rpm-build 0fba15
  if (out_reachable)
rpm-build 0fba15
    *out_reachable = g_steal_pointer (&ret_reachable);
rpm-build 0fba15
  return TRUE;
rpm-build 0fba15
}