Blame src/builder-cache.c

rpm-build c487f7
/* builder-cache.c
rpm-build c487f7
 *
rpm-build c487f7
 * Copyright (C) 2015 Red Hat, Inc
rpm-build c487f7
 *
rpm-build c487f7
 * This file is free software; you can redistribute it and/or modify it
rpm-build c487f7
 * under the terms of the GNU Lesser General Public License as
rpm-build c487f7
 * published by the Free Software Foundation; either version 2 of the
rpm-build c487f7
 * License, or (at your option) any later version.
rpm-build c487f7
 *
rpm-build c487f7
 * This file is distributed in the hope that it will be useful, but
rpm-build c487f7
 * WITHOUT ANY WARRANTY; without even the implied warranty of
rpm-build c487f7
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
rpm-build c487f7
 * Lesser General Public License for more details.
rpm-build c487f7
 *
rpm-build c487f7
 * You should have received a copy of the GNU Lesser General Public License
rpm-build c487f7
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
rpm-build c487f7
 *
rpm-build c487f7
 * Authors:
rpm-build c487f7
 *       Alexander Larsson <alexl@redhat.com>
rpm-build c487f7
 */
rpm-build c487f7
rpm-build c487f7
#include "config.h"
rpm-build c487f7
rpm-build c487f7
#include <string.h>
rpm-build c487f7
#include <fcntl.h>
rpm-build c487f7
#include <stdio.h>
rpm-build c487f7
#include <stdlib.h>
rpm-build c487f7
#include <sys/statfs.h>
rpm-build c487f7
rpm-build c487f7
#include <gio/gio.h>
rpm-build c487f7
#include <ostree.h>
rpm-build c487f7
#include "libglnx/libglnx.h"
rpm-build c487f7
rpm-build c487f7
#include "builder-flatpak-utils.h"
rpm-build c487f7
#include "builder-utils.h"
rpm-build c487f7
#include "builder-cache.h"
rpm-build c487f7
#include "builder-context.h"
rpm-build c487f7
rpm-build c487f7
struct BuilderCache
rpm-build c487f7
{
rpm-build c487f7
  GObject     parent;
rpm-build c487f7
  BuilderContext *context;
rpm-build c487f7
  GChecksum  *checksum;
rpm-build c487f7
  GFile      *app_dir;
rpm-build c487f7
  char       *branch;
rpm-build c487f7
  char       *stage;
rpm-build c487f7
  GHashTable *unused_stages;
rpm-build c487f7
  char       *last_parent;
rpm-build c487f7
  char       *current_checksum;
rpm-build c487f7
  OstreeRepo *repo;
rpm-build c487f7
  gboolean    disabled;
rpm-build c487f7
  OstreeRepoDevInoCache *devino_to_csum_cache;
rpm-build c487f7
};
rpm-build c487f7
rpm-build c487f7
typedef struct
rpm-build c487f7
{
rpm-build c487f7
  GObjectClass parent_class;
rpm-build c487f7
} BuilderCacheClass;
rpm-build c487f7
rpm-build c487f7
G_DEFINE_TYPE (BuilderCache, builder_cache, G_TYPE_OBJECT);
rpm-build c487f7
rpm-build c487f7
enum {
rpm-build c487f7
  PROP_0,
rpm-build c487f7
  PROP_CONTEXT,
rpm-build c487f7
  PROP_APP_DIR,
rpm-build c487f7
  PROP_BRANCH,
rpm-build c487f7
  LAST_PROP
rpm-build c487f7
};
rpm-build c487f7
rpm-build c487f7
#define OSTREE_GIO_FAST_QUERYINFO ("standard::name,standard::type,standard::size,standard::is-symlink,standard::symlink-target," \
rpm-build c487f7
                                   "unix::device,unix::inode,unix::mode,unix::uid,unix::gid,unix::rdev")
rpm-build c487f7
rpm-build c487f7
static GPtrArray   *builder_cache_get_changes_to (BuilderCache *self,
rpm-build c487f7
                                                  GFile        *current_root,
rpm-build c487f7
                                                  GPtrArray   **removals,
rpm-build c487f7
                                                  GError      **error);
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
builder_cache_finalize (GObject *object)
rpm-build c487f7
{
rpm-build c487f7
  BuilderCache *self = (BuilderCache *) object;
rpm-build c487f7
rpm-build c487f7
  g_clear_object (&self->context);
rpm-build c487f7
  g_clear_object (&self->app_dir);
rpm-build c487f7
  g_clear_object (&self->repo);
rpm-build c487f7
  g_checksum_free (self->checksum);
rpm-build c487f7
  g_free (self->branch);
rpm-build c487f7
  g_free (self->last_parent);
rpm-build c487f7
  g_free (self->stage);
rpm-build c487f7
  g_free (self->current_checksum);
rpm-build c487f7
  if (self->unused_stages)
rpm-build c487f7
    g_hash_table_unref (self->unused_stages);
rpm-build c487f7
rpm-build c487f7
  if (self->devino_to_csum_cache)
rpm-build c487f7
    ostree_repo_devino_cache_unref (self->devino_to_csum_cache);
rpm-build c487f7
rpm-build c487f7
  G_OBJECT_CLASS (builder_cache_parent_class)->finalize (object);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
builder_cache_get_property (GObject    *object,
rpm-build c487f7
                            guint       prop_id,
rpm-build c487f7
                            GValue     *value,
rpm-build c487f7
                            GParamSpec *pspec)
rpm-build c487f7
{
rpm-build c487f7
  BuilderCache *self = BUILDER_CACHE (object);
rpm-build c487f7
rpm-build c487f7
  switch (prop_id)
rpm-build c487f7
    {
rpm-build c487f7
    case PROP_CONTEXT:
rpm-build c487f7
      g_value_set_object (value, self->context);
rpm-build c487f7
      break;
rpm-build c487f7
rpm-build c487f7
    case PROP_APP_DIR:
rpm-build c487f7
      g_value_set_object (value, self->app_dir);
rpm-build c487f7
      break;
rpm-build c487f7
rpm-build c487f7
    case PROP_BRANCH:
rpm-build c487f7
      g_value_set_string (value, self->branch);
rpm-build c487f7
      break;
rpm-build c487f7
rpm-build c487f7
    default:
rpm-build c487f7
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
rpm-build c487f7
    }
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
builder_cache_set_property (GObject      *object,
rpm-build c487f7
                            guint         prop_id,
rpm-build c487f7
                            const GValue *value,
rpm-build c487f7
                            GParamSpec   *pspec)
rpm-build c487f7
{
rpm-build c487f7
  BuilderCache *self = BUILDER_CACHE (object);
rpm-build c487f7
rpm-build c487f7
  switch (prop_id)
rpm-build c487f7
    {
rpm-build c487f7
    case PROP_BRANCH:
rpm-build c487f7
      g_free (self->branch);
rpm-build c487f7
      self->branch = g_value_dup_string (value);
rpm-build c487f7
      break;
rpm-build c487f7
rpm-build c487f7
    case PROP_CONTEXT:
rpm-build c487f7
      g_set_object (&self->context, g_value_get_object (value));
rpm-build c487f7
      break;
rpm-build c487f7
rpm-build c487f7
    case PROP_APP_DIR:
rpm-build c487f7
      g_set_object (&self->app_dir, g_value_get_object (value));
rpm-build c487f7
      break;
rpm-build c487f7
rpm-build c487f7
    default:
rpm-build c487f7
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
rpm-build c487f7
    }
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
builder_cache_class_init (BuilderCacheClass *klass)
rpm-build c487f7
{
rpm-build c487f7
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
rpm-build c487f7
rpm-build c487f7
  object_class->finalize = builder_cache_finalize;
rpm-build c487f7
  object_class->get_property = builder_cache_get_property;
rpm-build c487f7
  object_class->set_property = builder_cache_set_property;
rpm-build c487f7
rpm-build c487f7
  g_object_class_install_property (object_class,
rpm-build c487f7
                                   PROP_CONTEXT,
rpm-build c487f7
                                   g_param_spec_object ("context",
rpm-build c487f7
                                                        "",
rpm-build c487f7
                                                        "",
rpm-build c487f7
                                                        BUILDER_TYPE_CONTEXT,
rpm-build c487f7
                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
rpm-build c487f7
  g_object_class_install_property (object_class,
rpm-build c487f7
                                   PROP_APP_DIR,
rpm-build c487f7
                                   g_param_spec_object ("app-dir",
rpm-build c487f7
                                                        "",
rpm-build c487f7
                                                        "",
rpm-build c487f7
                                                        G_TYPE_FILE,
rpm-build c487f7
                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
rpm-build c487f7
  g_object_class_install_property (object_class,
rpm-build c487f7
                                   PROP_BRANCH,
rpm-build c487f7
                                   g_param_spec_string ("branch",
rpm-build c487f7
                                                        "",
rpm-build c487f7
                                                        "",
rpm-build c487f7
                                                        NULL,
rpm-build c487f7
                                                        G_PARAM_READWRITE));
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
builder_cache_init (BuilderCache *self)
rpm-build c487f7
{
rpm-build c487f7
  self->checksum = g_checksum_new (G_CHECKSUM_SHA256);
rpm-build c487f7
  self->devino_to_csum_cache = ostree_repo_devino_cache_new ();
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
BuilderCache *
rpm-build c487f7
builder_cache_new (BuilderContext *context,
rpm-build c487f7
                   GFile      *app_dir,
rpm-build c487f7
                   const char *branch)
rpm-build c487f7
{
rpm-build c487f7
  return g_object_new (BUILDER_TYPE_CACHE,
rpm-build c487f7
                       "context", context,
rpm-build c487f7
                       "app-dir", app_dir,
rpm-build c487f7
                       "branch", branch,
rpm-build c487f7
                       NULL);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
GChecksum *
rpm-build c487f7
builder_cache_get_checksum (BuilderCache *self)
rpm-build c487f7
{
rpm-build c487f7
  return self->checksum;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
append_escaped_stage (GString *s,
rpm-build c487f7
                      const char *stage)
rpm-build c487f7
{
rpm-build c487f7
  while (*stage)
rpm-build c487f7
    {
rpm-build c487f7
      char c = *stage++;
rpm-build c487f7
      if (g_ascii_isalnum (c) ||
rpm-build c487f7
          c == '-' ||
rpm-build c487f7
          c == '_' ||
rpm-build c487f7
          c == '.')
rpm-build c487f7
        g_string_append_c (s, c);
rpm-build c487f7
      else
rpm-build c487f7
        g_string_append_printf (s, "%x", c);
rpm-build c487f7
    }
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static char *
rpm-build c487f7
get_ref (BuilderCache *self, const char *stage)
rpm-build c487f7
{
rpm-build c487f7
  GString *s = g_string_new (self->branch);
rpm-build c487f7
rpm-build c487f7
  g_string_append_c (s, '/');
rpm-build c487f7
rpm-build c487f7
  append_escaped_stage (s, stage);
rpm-build c487f7
rpm-build c487f7
  return g_string_free (s, FALSE);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
builder_cache_open (BuilderCache *self,
rpm-build c487f7
                    GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GKeyFile) config = NULL;
rpm-build c487f7
  g_autofree char *old_mfsp = NULL;
rpm-build c487f7
rpm-build c487f7
  self->repo = ostree_repo_new (builder_context_get_cache_dir (self->context));
rpm-build c487f7
rpm-build c487f7
  if (!g_file_query_exists (builder_context_get_cache_dir (self->context), NULL))
rpm-build c487f7
    {
rpm-build c487f7
      g_autoptr(GFile) parent = g_file_get_parent (builder_context_get_cache_dir (self->context));
rpm-build c487f7
rpm-build c487f7
      if (!flatpak_mkdir_p (parent, NULL, error))
rpm-build c487f7
        return FALSE;
rpm-build c487f7
rpm-build c487f7
      if (!ostree_repo_create (self->repo, OSTREE_REPO_MODE_BARE_USER_ONLY, NULL, error))
rpm-build c487f7
        return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_open (self->repo, NULL, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  config = ostree_repo_copy_config (self->repo);
rpm-build c487f7
rpm-build c487f7
  old_mfsp = g_key_file_get_value (config, "core", "min-free-space-percent", NULL);
rpm-build c487f7
  if (g_strcmp0 (old_mfsp, "0") != 0)
rpm-build c487f7
    {
rpm-build c487f7
      g_key_file_set_value (config, "core", "min-free-space-percent", "0");
rpm-build c487f7
rpm-build c487f7
      if (!ostree_repo_write_config (self->repo, config, error))
rpm-build c487f7
        return FALSE;
rpm-build c487f7
rpm-build c487f7
      /* Re-open */
rpm-build c487f7
      g_clear_object (&self->repo);
rpm-build c487f7
      self->repo = ostree_repo_new (builder_context_get_cache_dir (self->context));
rpm-build c487f7
      if (!ostree_repo_open (self->repo, NULL, error))
rpm-build c487f7
          return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  /* We don't need fsync on checkouts as they are transient, and we
rpm-build c487f7
     rely on the syncfs() in the transaction commit for commits. */
rpm-build c487f7
  ostree_repo_set_disable_fsync (self->repo, TRUE);
rpm-build c487f7
rpm-build c487f7
  /* At one point we used just the branch name as a ref, make sure to
rpm-build c487f7
   * remove this to handle using the branch as a subdir */
rpm-build c487f7
  ostree_repo_set_ref_immediate (self->repo,
rpm-build c487f7
                                 NULL,
rpm-build c487f7
                                 self->branch,
rpm-build c487f7
                                 NULL,
rpm-build c487f7
                                 NULL, NULL);
rpm-build c487f7
rpm-build c487f7
  /* List all stages first so we can purge unused ones at the end */
rpm-build c487f7
  if (!ostree_repo_list_refs (self->repo,
rpm-build c487f7
                              self->branch,
rpm-build c487f7
                              &self->unused_stages,
rpm-build c487f7
                              NULL, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
builder_cache_checkout (BuilderCache *self, const char *commit, gboolean delete_dir, GError **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GError) my_error = NULL;
rpm-build c487f7
  OstreeRepoCheckoutAtOptions options = { 0, };
rpm-build c487f7
rpm-build c487f7
  if (delete_dir)
rpm-build c487f7
    {
rpm-build c487f7
      if (!g_file_delete (self->app_dir, NULL, &my_error) &&
rpm-build c487f7
          !g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
rpm-build c487f7
        {
rpm-build c487f7
          g_propagate_error (error, g_steal_pointer (&my_error));
rpm-build c487f7
          return FALSE;
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      if (!flatpak_mkdir_p (self->app_dir, NULL, error))
rpm-build c487f7
        return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  /* If rofiles-fuse is disabled, we check out with force_copy
rpm-build c487f7
     because we want to force the checkout to not use
rpm-build c487f7
     hardlinks. Hard links into the cache without rofiles-fuse are notx
rpm-build c487f7
     safe, as the build could mutate the cache. */
rpm-build c487f7
  if (!builder_context_get_use_rofiles (self->context))
rpm-build c487f7
    options.force_copy = TRUE;
rpm-build c487f7
rpm-build c487f7
  options.mode = OSTREE_REPO_CHECKOUT_MODE_USER;
rpm-build c487f7
  options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
rpm-build c487f7
  options.devino_to_csum_cache = self->devino_to_csum_cache;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_checkout_at (self->repo, &options,
rpm-build c487f7
                                AT_FDCWD, flatpak_file_get_path_cached (self->app_dir),
rpm-build c487f7
                                commit, NULL, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  /* There is a bug in ostree (https://github.com/ostreedev/ostree/issues/326) that
rpm-build c487f7
     causes it to not reset mtime to 0 in them force_copy case. So we do that
rpm-build c487f7
     manually */
rpm-build c487f7
  if (options.force_copy &&
rpm-build c487f7
      !flatpak_zero_mtime (AT_FDCWD, flatpak_file_get_path_cached (self->app_dir),
rpm-build c487f7
                           NULL, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
builder_cache_has_checkout (BuilderCache *self)
rpm-build c487f7
{
rpm-build c487f7
  return self->disabled;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_cache_ensure_checkout (BuilderCache *self)
rpm-build c487f7
{
rpm-build c487f7
  if (builder_cache_has_checkout (self))
rpm-build c487f7
    return;
rpm-build c487f7
rpm-build c487f7
  if (self->last_parent)
rpm-build c487f7
    {
rpm-build c487f7
      g_autoptr(GError) error = NULL;
rpm-build c487f7
      g_print ("Everything cached, checking out from cache\n");
rpm-build c487f7
rpm-build c487f7
      if (!builder_cache_checkout (self, self->last_parent, TRUE, &error))
rpm-build c487f7
        g_error ("Failed to check out cache: %s", error->message);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  self->disabled = TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static char *
rpm-build c487f7
builder_cache_get_current_ref (BuilderCache *self)
rpm-build c487f7
{
rpm-build c487f7
  return get_ref (self, self->stage);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
builder_cache_lookup (BuilderCache *self,
rpm-build c487f7
                      const char   *stage)
rpm-build c487f7
{
rpm-build c487f7
  g_autofree char *commit = NULL;
rpm-build c487f7
  g_autofree char *ref = NULL;
rpm-build c487f7
  g_autoptr(GString) s = g_string_new ("");
rpm-build c487f7
rpm-build c487f7
  g_free (self->stage);
rpm-build c487f7
  self->stage = g_strdup (stage);
rpm-build c487f7
rpm-build c487f7
  append_escaped_stage (s, stage);
rpm-build c487f7
  g_hash_table_remove (self->unused_stages, s->str);
rpm-build c487f7
rpm-build c487f7
  g_free (self->current_checksum);
rpm-build c487f7
  self->current_checksum = g_strdup (g_checksum_get_string (self->checksum));
rpm-build c487f7
rpm-build c487f7
  /* Reset the checksum, but feed it previous checksum so we chain it */
rpm-build c487f7
  g_checksum_reset (self->checksum);
rpm-build c487f7
  builder_cache_checksum_str (self, self->current_checksum);
rpm-build c487f7
rpm-build c487f7
  if (self->disabled)
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  ref = builder_cache_get_current_ref (self);
rpm-build c487f7
  if (!ostree_repo_resolve_rev (self->repo, ref, TRUE, &commit, NULL))
rpm-build c487f7
    goto checkout;
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
  if (commit != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      g_autoptr(GVariant) variant = NULL;
rpm-build c487f7
      const gchar *subject;
rpm-build c487f7
rpm-build c487f7
      if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_COMMIT, commit,
rpm-build c487f7
                                     &variant, NULL))
rpm-build c487f7
        goto checkout;
rpm-build c487f7
rpm-build c487f7
      g_variant_get (variant, "(a{sv}aya(say)&s&stayay)", NULL, NULL, NULL,
rpm-build c487f7
                     &subject, NULL, NULL, NULL, NULL);
rpm-build c487f7
rpm-build c487f7
      if (strcmp (subject, self->current_checksum) == 0)
rpm-build c487f7
        {
rpm-build c487f7
          g_free (self->last_parent);
rpm-build c487f7
          self->last_parent = g_steal_pointer (&commit);
rpm-build c487f7
rpm-build c487f7
          return TRUE;
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
checkout:
rpm-build c487f7
  if (self->last_parent)
rpm-build c487f7
    {
rpm-build c487f7
      g_autoptr(GError) error = NULL;
rpm-build c487f7
      g_print ("Cache miss, checking out last cache hit\n");
rpm-build c487f7
rpm-build c487f7
      if (!builder_cache_checkout (self, self->last_parent, TRUE, &error))
rpm-build c487f7
        g_error ("Failed to check out cache: %s", error->message);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  self->disabled = TRUE; /* Don't use cache any more after first miss */
rpm-build c487f7
rpm-build c487f7
  return FALSE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
mtree_empty (OstreeMutableTree *mtree)
rpm-build c487f7
{
rpm-build c487f7
  GHashTable *files = ostree_mutable_tree_get_files (mtree);
rpm-build c487f7
  GHashTable *subdirs = ostree_mutable_tree_get_subdirs (mtree);
rpm-build c487f7
rpm-build c487f7
  return
rpm-build c487f7
    g_hash_table_size (files) == 0 &&
rpm-build c487f7
    g_hash_table_size (subdirs) == 0;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
/* This takes a mutable tree and an existing OstreeRepoFile, and recursively
rpm-build c487f7
 * removes all mtree files that already exists in the OstreeRepoFile.
rpm-build c487f7
 * This is very useful to create a commit with just the new files, which
rpm-build c487f7
 * we can then check out in order to get a the new hardlinks to the
rpm-build c487f7
 * cache repo.
rpm-build c487f7
 */
rpm-build c487f7
static gboolean
rpm-build c487f7
mtree_prune_old_files (OstreeMutableTree *mtree,
rpm-build c487f7
                       OstreeRepoFile *old,
rpm-build c487f7
                       GError **error)
rpm-build c487f7
{
rpm-build c487f7
  GHashTable *files = ostree_mutable_tree_get_files (mtree);
rpm-build c487f7
  GHashTable *subdirs = ostree_mutable_tree_get_subdirs (mtree);
rpm-build c487f7
  GHashTableIter iter;
rpm-build c487f7
  gpointer key, value;
rpm-build c487f7
rpm-build c487f7
  ostree_mutable_tree_set_contents_checksum (mtree, NULL);
rpm-build c487f7
rpm-build c487f7
  if (old != NULL && !ostree_repo_file_ensure_resolved (old, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  g_hash_table_iter_init (&iter, files);
rpm-build c487f7
  while (g_hash_table_iter_next (&iter, &key, &value))
rpm-build c487f7
    {
rpm-build c487f7
      const char *name = key;
rpm-build c487f7
      const char *csum = value;
rpm-build c487f7
      int n = -1;
rpm-build c487f7
      gboolean is_dir;
rpm-build c487f7
      g_autoptr(GVariant) container = NULL;
rpm-build c487f7
      gboolean same = FALSE;
rpm-build c487f7
rpm-build c487f7
      if (old)
rpm-build c487f7
        n = ostree_repo_file_tree_find_child  (old, name, &is_dir, &container);
rpm-build c487f7
rpm-build c487f7
      if (n >= 0)
rpm-build c487f7
        {
rpm-build c487f7
          if (!is_dir)
rpm-build c487f7
            {
rpm-build c487f7
              g_autoptr(GVariant) old_csum_bytes = NULL;
rpm-build c487f7
              g_autofree char *old_csum = NULL;
rpm-build c487f7
rpm-build c487f7
              g_variant_get_child (container, n,
rpm-build c487f7
                                   "(@s@ay)", NULL, &old_csum_bytes);
rpm-build c487f7
              old_csum = ostree_checksum_from_bytes_v (old_csum_bytes);
rpm-build c487f7
rpm-build c487f7
              if (strcmp (old_csum, csum) == 0)
rpm-build c487f7
                same = TRUE; /* Modified file */
rpm-build c487f7
            }
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      if (same)
rpm-build c487f7
        g_hash_table_iter_remove (&iter);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  g_hash_table_iter_init (&iter, subdirs);
rpm-build c487f7
  while (g_hash_table_iter_next (&iter, &key, &value))
rpm-build c487f7
    {
rpm-build c487f7
      const char *name = key;
rpm-build c487f7
      OstreeMutableTree *subdir = value;
rpm-build c487f7
      g_autoptr(GFile) old_subdir = NULL;
rpm-build c487f7
      int n = -1;
rpm-build c487f7
      gboolean is_dir;
rpm-build c487f7
rpm-build c487f7
      if (old)
rpm-build c487f7
        n = ostree_repo_file_tree_find_child  (old, name, &is_dir, NULL);
rpm-build c487f7
rpm-build c487f7
      if (n >= 0 && is_dir)
rpm-build c487f7
        old_subdir = g_file_get_child (G_FILE (old), name);
rpm-build c487f7
rpm-build c487f7
      if (!mtree_prune_old_files (subdir, OSTREE_REPO_FILE (old_subdir), error))
rpm-build c487f7
        return FALSE;
rpm-build c487f7
rpm-build c487f7
      if (mtree_empty (subdir))
rpm-build c487f7
        g_hash_table_iter_remove (&iter);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static OstreeRepoCommitFilterResult
rpm-build c487f7
commit_filter (OstreeRepo *repo,
rpm-build c487f7
               const char *path,
rpm-build c487f7
               GFileInfo  *file_info,
rpm-build c487f7
               gpointer    commit_data)
rpm-build c487f7
{
rpm-build c487f7
  guint mode;
rpm-build c487f7
rpm-build c487f7
  /* No user info */
rpm-build c487f7
  g_file_info_set_attribute_uint32 (file_info, "unix::uid", 0);
rpm-build c487f7
  g_file_info_set_attribute_uint32 (file_info, "unix::gid", 0);
rpm-build c487f7
rpm-build c487f7
  /* In flatpak, there is no real reason for files to have different
rpm-build c487f7
   * permissions based on the group or user really, everything is
rpm-build c487f7
   * always used readonly for everyone. Having things be writeable
rpm-build c487f7
   * for anyone but the user just causes risks for the system-installed
rpm-build c487f7
   * case. So, we canonicalize the mode to writable only by the user,
rpm-build c487f7
   * readable to all, and executable for all for directories and
rpm-build c487f7
   * files that the user can execute.
rpm-build c487f7
  */
rpm-build c487f7
  mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
rpm-build c487f7
  if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
rpm-build c487f7
    mode = 0755 | S_IFDIR;
rpm-build c487f7
  else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
rpm-build c487f7
    {
rpm-build c487f7
      /* If use can execute, make executable by all */
rpm-build c487f7
      if (mode & S_IXUSR)
rpm-build c487f7
        mode = 0755 | S_IFREG;
rpm-build c487f7
      else /* otherwise executable by none */
rpm-build c487f7
        mode = 0644 | S_IFREG;
rpm-build c487f7
    }
rpm-build c487f7
  g_file_info_set_attribute_uint32 (file_info, "unix::mode", mode);
rpm-build c487f7
rpm-build c487f7
  return OSTREE_REPO_COMMIT_FILTER_ALLOW;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
builder_cache_commit (BuilderCache *self,
rpm-build c487f7
                      const char   *body,
rpm-build c487f7
                      GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  const char *current = NULL;
rpm-build c487f7
  OstreeRepoCommitModifier *modifier = NULL;
rpm-build c487f7
rpm-build c487f7
  g_autoptr(OstreeMutableTree) mtree = NULL;
rpm-build c487f7
  g_autoptr(GFile) root = NULL;
rpm-build c487f7
  g_autofree char *commit_checksum = NULL;
rpm-build c487f7
  g_autofree char *new_commit_checksum = NULL;
rpm-build c487f7
  gboolean res = FALSE;
rpm-build c487f7
  g_autofree char *ref = NULL;
rpm-build c487f7
  g_autoptr(GFile) last_root = NULL;
rpm-build c487f7
  g_autoptr(GFile) new_root = NULL;
rpm-build c487f7
  g_autoptr(GPtrArray) changes = NULL;
rpm-build c487f7
  g_autoptr(GPtrArray) removals = NULL;
rpm-build c487f7
  g_autoptr(GVariantDict) metadata_dict = NULL;
rpm-build c487f7
  g_autoptr(GVariant) metadata = NULL;
rpm-build c487f7
  g_autoptr(GVariant) changesv = NULL;
rpm-build c487f7
  g_autoptr(GVariant) removalsv = NULL;
rpm-build c487f7
  g_autoptr(GVariant) changesvz = NULL;
rpm-build c487f7
  g_autoptr(GVariant) removalsvz = NULL;
rpm-build c487f7
rpm-build c487f7
  g_print ("Committing stage %s to cache\n", self->stage);
rpm-build c487f7
rpm-build c487f7
  /* We set all mtimes to 0 during a commit, to simulate what would happen when
rpm-build c487f7
     running via flatpak deploy (and also if we checked out from the cache). */
rpm-build c487f7
  if (!flatpak_zero_mtime (AT_FDCWD, flatpak_file_get_path_cached (self->app_dir),
rpm-build c487f7
                           NULL, NULL))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_prepare_transaction (self->repo, NULL, NULL, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  mtree = ostree_mutable_tree_new ();
rpm-build c487f7
rpm-build c487f7
  modifier = ostree_repo_commit_modifier_new (OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS,
rpm-build c487f7
                                              (OstreeRepoCommitFilter) commit_filter, NULL, NULL);
rpm-build c487f7
  if (self->devino_to_csum_cache)
rpm-build c487f7
    ostree_repo_commit_modifier_set_devino_cache (modifier, self->devino_to_csum_cache);
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_write_directory_to_mtree (self->repo, self->app_dir,
rpm-build c487f7
                                             mtree, modifier, NULL, error))
rpm-build c487f7
    goto out;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_write_mtree (self->repo, mtree, &root, NULL, error))
rpm-build c487f7
    goto out;
rpm-build c487f7
rpm-build c487f7
  changes = builder_cache_get_changes_to (self, root, &removals, NULL);
rpm-build c487f7
rpm-build c487f7
  metadata_dict = g_variant_dict_new (NULL);
rpm-build c487f7
rpm-build c487f7
  changesv = g_variant_ref_sink (g_variant_new_strv ((const gchar * const  *) changes->pdata, changes->len));
rpm-build c487f7
  changesvz = flatpak_variant_compress (changesv);
rpm-build c487f7
  g_variant_dict_insert_value (metadata_dict, "changesz", changesvz);
rpm-build c487f7
rpm-build c487f7
  removalsv = g_variant_ref_sink (g_variant_new_strv ((const gchar * const  *) removals->pdata, removals->len));
rpm-build c487f7
  removalsvz = flatpak_variant_compress (removalsv);
rpm-build c487f7
  g_variant_dict_insert_value (metadata_dict, "removalsz", removalsvz);
rpm-build c487f7
rpm-build c487f7
  metadata = g_variant_ref_sink (g_variant_dict_end (metadata_dict));
rpm-build c487f7
rpm-build c487f7
  current = self->current_checksum;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_write_commit (self->repo, self->last_parent, current, body, metadata,
rpm-build c487f7
                                 OSTREE_REPO_FILE (root),
rpm-build c487f7
                                 &commit_checksum, NULL, error))
rpm-build c487f7
    goto out;
rpm-build c487f7
rpm-build c487f7
  ref = builder_cache_get_current_ref (self);
rpm-build c487f7
  ostree_repo_transaction_set_ref (self->repo, NULL, ref, commit_checksum);
rpm-build c487f7
rpm-build c487f7
  if (self->last_parent &&
rpm-build c487f7
      !ostree_repo_read_commit (self->repo, self->last_parent, &last_root, NULL, NULL, error))
rpm-build c487f7
    goto out;
rpm-build c487f7
rpm-build c487f7
  if (!mtree_prune_old_files (mtree, OSTREE_REPO_FILE (last_root), error))
rpm-build c487f7
    goto out;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_write_mtree (self->repo, mtree, &new_root, NULL, error))
rpm-build c487f7
    goto out;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_write_commit (self->repo, NULL, current, body, metadata,
rpm-build c487f7
                                 OSTREE_REPO_FILE (new_root),
rpm-build c487f7
                                 &new_commit_checksum, NULL, error))
rpm-build c487f7
    goto out;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_commit_transaction (self->repo, NULL, NULL, error))
rpm-build c487f7
    goto out;
rpm-build c487f7
rpm-build c487f7
  /* Check out the just commited cache so we hardlinks to the cache */
rpm-build c487f7
  if (builder_context_get_use_rofiles (self->context) &&
rpm-build c487f7
      !builder_cache_checkout (self, new_commit_checksum, FALSE, error))
rpm-build c487f7
    goto out;
rpm-build c487f7
rpm-build c487f7
  g_free (self->last_parent);
rpm-build c487f7
  self->last_parent = g_steal_pointer (&commit_checksum);
rpm-build c487f7
rpm-build c487f7
  res = TRUE;
rpm-build c487f7
rpm-build c487f7
out:
rpm-build c487f7
  if (!res)
rpm-build c487f7
    {
rpm-build c487f7
      if (!ostree_repo_abort_transaction (self->repo, NULL, NULL))
rpm-build c487f7
        g_warning ("failed to abort transaction");
rpm-build c487f7
    }
rpm-build c487f7
  if (modifier)
rpm-build c487f7
    ostree_repo_commit_modifier_unref (modifier);
rpm-build c487f7
rpm-build c487f7
  return res;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
typedef struct {
rpm-build c487f7
  dev_t dev;
rpm-build c487f7
  ino_t ino;
rpm-build c487f7
  char checksum[OSTREE_SHA256_STRING_LEN+1];
rpm-build c487f7
} OstreeDevIno;
rpm-build c487f7
rpm-build c487f7
static const char *
rpm-build c487f7
devino_cache_lookup (OstreeRepoDevInoCache *devino_to_csum_cache,
rpm-build c487f7
                     guint32               device,
rpm-build c487f7
                     guint32               inode)
rpm-build c487f7
{
rpm-build c487f7
  OstreeDevIno dev_ino_key;
rpm-build c487f7
  OstreeDevIno *dev_ino_val;
rpm-build c487f7
  GHashTable *cache = (GHashTable *)devino_to_csum_cache;
rpm-build c487f7
rpm-build c487f7
  if (devino_to_csum_cache == NULL)
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  dev_ino_key.dev = device;
rpm-build c487f7
  dev_ino_key.ino = inode;
rpm-build c487f7
  dev_ino_val = g_hash_table_lookup (cache, &dev_ino_key);
rpm-build c487f7
rpm-build c487f7
  if (!dev_ino_val)
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  return dev_ino_val->checksum;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
get_file_checksum (OstreeRepoDevInoCache *devino_to_csum_cache,
rpm-build c487f7
                   GFile *f,
rpm-build c487f7
                   GFileInfo *f_info,
rpm-build c487f7
                   char  **out_checksum,
rpm-build c487f7
                   GCancellable *cancellable,
rpm-build c487f7
                   GError   **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autofree char *ret_checksum = NULL;
rpm-build c487f7
  g_autofree guchar *csum = NULL;
rpm-build c487f7
rpm-build c487f7
  if (OSTREE_IS_REPO_FILE (f))
rpm-build c487f7
    {
rpm-build c487f7
      ret_checksum = g_strdup (ostree_repo_file_get_checksum ((OstreeRepoFile*)f));
rpm-build c487f7
    }
rpm-build c487f7
  else
rpm-build c487f7
    {
rpm-build c487f7
      const char *cached = devino_cache_lookup (devino_to_csum_cache,
rpm-build c487f7
                                                g_file_info_get_attribute_uint32 (f_info, "unix::device"),
rpm-build c487f7
                                                g_file_info_get_attribute_uint64 (f_info, "unix::inode"));
rpm-build c487f7
      if (cached)
rpm-build c487f7
        ret_checksum = g_strdup (cached);
rpm-build c487f7
      else
rpm-build c487f7
        {
rpm-build c487f7
          g_autoptr(GInputStream) in = NULL;
rpm-build c487f7
rpm-build c487f7
          if (g_file_info_get_file_type (f_info) == G_FILE_TYPE_REGULAR)
rpm-build c487f7
            {
rpm-build c487f7
              in = (GInputStream*)g_file_read (f, cancellable, error);
rpm-build c487f7
              if (!in)
rpm-build c487f7
                return FALSE;
rpm-build c487f7
            }
rpm-build c487f7
rpm-build c487f7
          if (!ostree_checksum_file_from_input (f_info, NULL, in,
rpm-build c487f7
                                                OSTREE_OBJECT_TYPE_FILE,
rpm-build c487f7
                                                &csum, cancellable, error))
rpm-build c487f7
            return FALSE;
rpm-build c487f7
rpm-build c487f7
          ret_checksum = ostree_checksum_from_bytes (csum);
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  *out_checksum = g_steal_pointer (&ret_checksum);
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
diff_files (OstreeRepoDevInoCache *devino_to_csum_cache,
rpm-build c487f7
            GFile           *a,
rpm-build c487f7
            GFileInfo       *a_info,
rpm-build c487f7
            GFile           *b,
rpm-build c487f7
            GFileInfo       *b_info,
rpm-build c487f7
            gboolean        *was_changed,
rpm-build c487f7
            GCancellable    *cancellable,
rpm-build c487f7
            GError         **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autofree char *checksum_a = NULL;
rpm-build c487f7
  g_autofree char *checksum_b = NULL;
rpm-build c487f7
rpm-build c487f7
  if (!get_file_checksum (devino_to_csum_cache, a, a_info, &checksum_a, cancellable, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  if (!get_file_checksum (devino_to_csum_cache, b, b_info, &checksum_b, cancellable, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  *was_changed = strcmp (checksum_a, checksum_b) != 0;
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
diff_add_dir_recurse (GFile          *d,
rpm-build c487f7
                      GPtrArray      *added,
rpm-build c487f7
                      GCancellable   *cancellable,
rpm-build c487f7
                      GError        **error)
rpm-build c487f7
{
rpm-build c487f7
  GError *temp_error = NULL;
rpm-build c487f7
  g_autoptr(GFileEnumerator) dir_enum = NULL;
rpm-build c487f7
  g_autoptr(GFile) child = NULL;
rpm-build c487f7
  g_autoptr(GFileInfo) child_info = NULL;
rpm-build c487f7
rpm-build c487f7
  dir_enum = g_file_enumerate_children (d, OSTREE_GIO_FAST_QUERYINFO,
rpm-build c487f7
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
rpm-build c487f7
                                        cancellable,
rpm-build c487f7
                                        error);
rpm-build c487f7
  if (!dir_enum)
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  while ((child_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      const char *name;
rpm-build c487f7
rpm-build c487f7
      name = g_file_info_get_name (child_info);
rpm-build c487f7
rpm-build c487f7
      g_clear_object (&child);
rpm-build c487f7
      child = g_file_get_child (d, name);
rpm-build c487f7
rpm-build c487f7
      g_ptr_array_add (added, g_object_ref (child));
rpm-build c487f7
rpm-build c487f7
      if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY)
rpm-build c487f7
        {
rpm-build c487f7
          if (!diff_add_dir_recurse (child, added, cancellable, error))
rpm-build c487f7
            return FALSE;
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      g_clear_object (&child_info);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (temp_error != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      g_propagate_error (error, temp_error);
rpm-build c487f7
      return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
diff_dirs (OstreeRepoDevInoCache *devino_to_csum_cache,
rpm-build c487f7
           GFile          *a,
rpm-build c487f7
           GFile          *b,
rpm-build c487f7
           GPtrArray      *changed,
rpm-build c487f7
           GCancellable   *cancellable,
rpm-build c487f7
           GError        **error)
rpm-build c487f7
{
rpm-build c487f7
  GError *temp_error = NULL;
rpm-build c487f7
  g_autoptr(GFileEnumerator) dir_enum = NULL;
rpm-build c487f7
  g_autoptr(GFile) child_a = NULL;
rpm-build c487f7
  g_autoptr(GFile) child_b = NULL;
rpm-build c487f7
  g_autoptr(GFileInfo) child_a_info = NULL;
rpm-build c487f7
  g_autoptr(GFileInfo) child_b_info = NULL;
rpm-build c487f7
rpm-build c487f7
  if (a == NULL)
rpm-build c487f7
    {
rpm-build c487f7
      if (!diff_add_dir_recurse (b, changed, cancellable, error))
rpm-build c487f7
        return FALSE;
rpm-build c487f7
rpm-build c487f7
      return TRUE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  dir_enum = g_file_enumerate_children (a, OSTREE_GIO_FAST_QUERYINFO,
rpm-build c487f7
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
rpm-build c487f7
                                        cancellable, error);
rpm-build c487f7
  if (!dir_enum)
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  while ((child_a_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      const char *name;
rpm-build c487f7
      GFileType child_a_type;
rpm-build c487f7
      GFileType child_b_type;
rpm-build c487f7
rpm-build c487f7
      name = g_file_info_get_name (child_a_info);
rpm-build c487f7
rpm-build c487f7
      g_clear_object (&child_a);
rpm-build c487f7
      child_a = g_file_get_child (a, name);
rpm-build c487f7
      child_a_type = g_file_info_get_file_type (child_a_info);
rpm-build c487f7
rpm-build c487f7
      g_clear_object (&child_b);
rpm-build c487f7
      child_b = g_file_get_child (b, name);
rpm-build c487f7
rpm-build c487f7
      g_clear_object (&child_b_info);
rpm-build c487f7
      child_b_info = g_file_query_info (child_b, OSTREE_GIO_FAST_QUERYINFO,
rpm-build c487f7
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
rpm-build c487f7
                                        cancellable,
rpm-build c487f7
                                        &temp_error);
rpm-build c487f7
      if (!child_b_info)
rpm-build c487f7
        {
rpm-build c487f7
          if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
rpm-build c487f7
            {
rpm-build c487f7
              g_clear_error (&temp_error);
rpm-build c487f7
              /* Removed, ignore */
rpm-build c487f7
            }
rpm-build c487f7
          else
rpm-build c487f7
            {
rpm-build c487f7
              g_propagate_error (error, temp_error);
rpm-build c487f7
              return FALSE;
rpm-build c487f7
            }
rpm-build c487f7
        }
rpm-build c487f7
      else
rpm-build c487f7
        {
rpm-build c487f7
          child_b_type = g_file_info_get_file_type (child_b_info);
rpm-build c487f7
          if (child_a_type != child_b_type)
rpm-build c487f7
            {
rpm-build c487f7
              g_ptr_array_add (changed, g_object_ref (child_b));
rpm-build c487f7
            }
rpm-build c487f7
          else
rpm-build c487f7
            {
rpm-build c487f7
              gboolean was_changed = FALSE;
rpm-build c487f7
rpm-build c487f7
              if (!diff_files (devino_to_csum_cache,
rpm-build c487f7
                               child_a, child_a_info,
rpm-build c487f7
                               child_b, child_b_info,
rpm-build c487f7
                               &was_changed,
rpm-build c487f7
                               cancellable, error))
rpm-build c487f7
                return FALSE;
rpm-build c487f7
rpm-build c487f7
              if (was_changed)
rpm-build c487f7
                g_ptr_array_add (changed, g_object_ref (child_b));
rpm-build c487f7
rpm-build c487f7
              if (child_a_type == G_FILE_TYPE_DIRECTORY)
rpm-build c487f7
                {
rpm-build c487f7
                  if (!diff_dirs (devino_to_csum_cache, child_a, child_b, changed,
rpm-build c487f7
                                  cancellable, error))
rpm-build c487f7
                    return FALSE;
rpm-build c487f7
                }
rpm-build c487f7
            }
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      g_clear_object (&child_a_info);
rpm-build c487f7
    }
rpm-build c487f7
  if (temp_error != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      g_propagate_error (error, temp_error);
rpm-build c487f7
      return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  g_clear_object (&dir_enum);
rpm-build c487f7
  dir_enum = g_file_enumerate_children (b, OSTREE_GIO_FAST_QUERYINFO,
rpm-build c487f7
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
rpm-build c487f7
                                        cancellable, error);
rpm-build c487f7
  if (!dir_enum)
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  g_clear_object (&child_b_info);
rpm-build c487f7
  while ((child_b_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      const char *name;
rpm-build c487f7
rpm-build c487f7
      name = g_file_info_get_name (child_b_info);
rpm-build c487f7
rpm-build c487f7
      g_clear_object (&child_a);
rpm-build c487f7
      child_a = g_file_get_child (a, name);
rpm-build c487f7
rpm-build c487f7
      g_clear_object (&child_b);
rpm-build c487f7
      child_b = g_file_get_child (b, name);
rpm-build c487f7
rpm-build c487f7
      g_clear_object (&child_a_info);
rpm-build c487f7
      child_a_info = g_file_query_info (child_a, OSTREE_GIO_FAST_QUERYINFO,
rpm-build c487f7
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
rpm-build c487f7
                                        cancellable,
rpm-build c487f7
                                        &temp_error);
rpm-build c487f7
      if (!child_a_info)
rpm-build c487f7
        {
rpm-build c487f7
          if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
rpm-build c487f7
            {
rpm-build c487f7
              g_clear_error (&temp_error);
rpm-build c487f7
              g_ptr_array_add (changed, g_object_ref (child_b));
rpm-build c487f7
              if (g_file_info_get_file_type (child_b_info) == G_FILE_TYPE_DIRECTORY)
rpm-build c487f7
                {
rpm-build c487f7
                  if (!diff_add_dir_recurse (child_b, changed, cancellable, error))
rpm-build c487f7
                    return FALSE;
rpm-build c487f7
                }
rpm-build c487f7
            }
rpm-build c487f7
          else
rpm-build c487f7
            {
rpm-build c487f7
              g_propagate_error (error, temp_error);
rpm-build c487f7
              return FALSE;
rpm-build c487f7
            }
rpm-build c487f7
        }
rpm-build c487f7
      g_clear_object (&child_b_info);
rpm-build c487f7
    }
rpm-build c487f7
  if (temp_error != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      g_propagate_error (error, temp_error);
rpm-build c487f7
      return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
builder_cache_get_outstanding_changes (BuilderCache *self,
rpm-build c487f7
                                       GPtrArray   **changed_out,
rpm-build c487f7
                                       GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GPtrArray) changed = g_ptr_array_new_with_free_func (g_object_unref);
rpm-build c487f7
  g_autoptr(GPtrArray) changed_paths = g_ptr_array_new_with_free_func (g_free);
rpm-build c487f7
  g_autoptr(GFile) last_root = NULL;
rpm-build c487f7
  int i;
rpm-build c487f7
rpm-build c487f7
  if (self->last_parent &&
rpm-build c487f7
      !ostree_repo_read_commit (self->repo, self->last_parent, &last_root, NULL, NULL, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  if (!diff_dirs (self->devino_to_csum_cache,
rpm-build c487f7
                  last_root,
rpm-build c487f7
                  self->app_dir,
rpm-build c487f7
                  changed,
rpm-build c487f7
                  NULL, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  for (i = 0; i < changed->len; i++)
rpm-build c487f7
    {
rpm-build c487f7
      GFile *changed_file = g_ptr_array_index (changed, i);
rpm-build c487f7
      char *path = g_file_get_relative_path (self->app_dir, changed_file);
rpm-build c487f7
      g_ptr_array_add (changed_paths, path);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (changed_out)
rpm-build c487f7
    *changed_out = g_steal_pointer (&changed_paths);
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static int
rpm-build c487f7
cmpstringp (const void *p1, const void *p2)
rpm-build c487f7
{
rpm-build c487f7
  return strcmp (*(char * const *) p1, *(char * const *) p2);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static GPtrArray *
rpm-build c487f7
get_changes (BuilderCache *self,
rpm-build c487f7
             GFile       *from,
rpm-build c487f7
             GFile       *to,
rpm-build c487f7
             GPtrArray  **removed_out,
rpm-build c487f7
             GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GPtrArray) added = g_ptr_array_new_with_free_func (g_object_unref);
rpm-build c487f7
  g_autoptr(GPtrArray) modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref);
rpm-build c487f7
  g_autoptr(GPtrArray) removed = g_ptr_array_new_with_free_func (g_object_unref);
rpm-build c487f7
  g_autoptr(GPtrArray) changed_paths = g_ptr_array_new_with_free_func (g_free);
rpm-build c487f7
  int i;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_diff_dirs (OSTREE_DIFF_FLAGS_NONE,
rpm-build c487f7
                         from,
rpm-build c487f7
                         to,
rpm-build c487f7
                         modified,
rpm-build c487f7
                         removed,
rpm-build c487f7
                         added,
rpm-build c487f7
                         NULL, error))
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  for (i = 0; i < added->len; i++)
rpm-build c487f7
    {
rpm-build c487f7
      char *path = g_file_get_relative_path (to, g_ptr_array_index (added, i));
rpm-build c487f7
      g_ptr_array_add (changed_paths, path);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  for (i = 0; i < modified->len; i++)
rpm-build c487f7
    {
rpm-build c487f7
      OstreeDiffItem *modified_item = g_ptr_array_index (modified, i);
rpm-build c487f7
      char *path = g_file_get_relative_path (to, modified_item->target);
rpm-build c487f7
      g_ptr_array_add (changed_paths, path);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  g_ptr_array_sort (changed_paths, cmpstringp);
rpm-build c487f7
rpm-build c487f7
  if (removed_out)
rpm-build c487f7
    {
rpm-build c487f7
      GPtrArray *removed_paths = g_ptr_array_new_with_free_func (g_free);
rpm-build c487f7
rpm-build c487f7
      for (i = 0; i < removed->len; i++)
rpm-build c487f7
        {
rpm-build c487f7
          char *path = g_file_get_relative_path (to, g_ptr_array_index (removed, i));
rpm-build c487f7
          g_ptr_array_add (removed_paths, path);
rpm-build c487f7
        }
rpm-build c487f7
      *removed_out = removed_paths;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return g_steal_pointer (&changed_paths);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
/* This returns removals too */
rpm-build c487f7
static GPtrArray *
rpm-build c487f7
get_all_changes (BuilderCache *self,
rpm-build c487f7
                 GFile       *from,
rpm-build c487f7
                 GFile       *to,
rpm-build c487f7
                 GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GPtrArray) added = g_ptr_array_new_with_free_func (g_object_unref);
rpm-build c487f7
  g_autoptr(GPtrArray) modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref);
rpm-build c487f7
  g_autoptr(GPtrArray) removed = g_ptr_array_new_with_free_func (g_object_unref);
rpm-build c487f7
  g_autoptr(GPtrArray) changed_paths = g_ptr_array_new_with_free_func (g_free);
rpm-build c487f7
  int i;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_diff_dirs (OSTREE_DIFF_FLAGS_NONE,
rpm-build c487f7
                         from,
rpm-build c487f7
                         to,
rpm-build c487f7
                         modified,
rpm-build c487f7
                         removed,
rpm-build c487f7
                         added,
rpm-build c487f7
                         NULL, error))
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  for (i = 0; i < added->len; i++)
rpm-build c487f7
    {
rpm-build c487f7
      char *path = g_file_get_relative_path (to, g_ptr_array_index (added, i));
rpm-build c487f7
      g_ptr_array_add (changed_paths, path);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  for (i = 0; i < modified->len; i++)
rpm-build c487f7
    {
rpm-build c487f7
      OstreeDiffItem *modified_item = g_ptr_array_index (modified, i);
rpm-build c487f7
      char *path = g_file_get_relative_path (to, modified_item->target);
rpm-build c487f7
      g_ptr_array_add (changed_paths, path);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  for (i = 0; i < removed->len; i++)
rpm-build c487f7
    {
rpm-build c487f7
      char *path = g_file_get_relative_path (to, g_ptr_array_index (removed, i));
rpm-build c487f7
      g_ptr_array_add (changed_paths, path);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  g_ptr_array_sort (changed_paths, cmpstringp);
rpm-build c487f7
rpm-build c487f7
  return g_steal_pointer (&changed_paths);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
/* This returns removals too */
rpm-build c487f7
GPtrArray *
rpm-build c487f7
builder_cache_get_all_changes (BuilderCache *self,
rpm-build c487f7
                               GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GFile) init_root = NULL;
rpm-build c487f7
  g_autoptr(GFile) finish_root = NULL;
rpm-build c487f7
  g_autofree char *init_commit = NULL;
rpm-build c487f7
  g_autofree char *finish_commit = NULL;
rpm-build c487f7
  g_autofree char *init_ref = get_ref (self, "init");
rpm-build c487f7
  g_autofree char *finish_ref = get_ref (self, "finish");
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_resolve_rev (self->repo, init_ref, FALSE, &init_commit, NULL))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_resolve_rev (self->repo, finish_ref, FALSE, &finish_commit, NULL))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_read_commit (self->repo, init_commit, &init_root, NULL, NULL, error))
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_read_commit (self->repo, finish_commit, &finish_root, NULL, NULL, error))
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  return get_all_changes (self, init_root, finish_root, error);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static GPtrArray   *
rpm-build c487f7
builder_cache_get_changes_to (BuilderCache *self,
rpm-build c487f7
                              GFile        *current_root,
rpm-build c487f7
                              GPtrArray   **removals,
rpm-build c487f7
                              GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GFile) parent_root = NULL;
rpm-build c487f7
rpm-build c487f7
  if (self->last_parent != NULL &&
rpm-build c487f7
      !ostree_repo_read_commit (self->repo, self->last_parent, &parent_root, NULL, NULL, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  return get_changes (self, parent_root, current_root, removals, error);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
GPtrArray   *
rpm-build c487f7
builder_cache_get_changes (BuilderCache *self,
rpm-build c487f7
                           GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GFile) current_root = NULL;
rpm-build c487f7
  g_autoptr(GFile) parent_root = NULL;
rpm-build c487f7
  g_autoptr(GVariant) variant = NULL;
rpm-build c487f7
  g_autoptr(GVariant) commit_metadata = NULL;
rpm-build c487f7
  g_autofree char *parent_commit = NULL;
rpm-build c487f7
  g_autoptr(GVariant) changesz_v = NULL;
rpm-build c487f7
  g_autoptr(GVariant) changes_v = NULL;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_read_commit (self->repo, self->last_parent, &current_root, NULL, NULL, error))
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_COMMIT, self->last_parent,
rpm-build c487f7
                                 &variant, NULL))
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  commit_metadata = g_variant_get_child_value (variant, 0);
rpm-build c487f7
  changesz_v = g_variant_lookup_value (commit_metadata, "changesz", G_VARIANT_TYPE_BYTESTRING);
rpm-build c487f7
rpm-build c487f7
  if (changesz_v)
rpm-build c487f7
    changes_v = flatpak_variant_uncompress (changesz_v, G_VARIANT_TYPE ("as"));
rpm-build c487f7
  else
rpm-build c487f7
    changes_v = g_variant_lookup_value (commit_metadata, "changes", G_VARIANT_TYPE ("as"));
rpm-build c487f7
rpm-build c487f7
  if (changes_v)
rpm-build c487f7
    {
rpm-build c487f7
      g_autoptr(GPtrArray) changed_paths = g_ptr_array_new_with_free_func (g_free);
rpm-build c487f7
      int i;
rpm-build c487f7
rpm-build c487f7
      for (i = 0; i < g_variant_n_children (changes_v); i++)
rpm-build c487f7
        {
rpm-build c487f7
          char *str;
rpm-build c487f7
          g_variant_get_child (changes_v, i, "s", &str);
rpm-build c487f7
          g_ptr_array_add (changed_paths, str);
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      return g_steal_pointer (&changed_paths);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  parent_commit = ostree_commit_get_parent (variant);
rpm-build c487f7
  if (parent_commit != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      if (!ostree_repo_read_commit (self->repo, parent_commit, &parent_root, NULL, NULL, error))
rpm-build c487f7
        return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return get_changes (self, parent_root, current_root, NULL, error);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
GPtrArray   *
rpm-build c487f7
builder_cache_get_files (BuilderCache *self,
rpm-build c487f7
                         GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GFile) current_root = NULL;
rpm-build c487f7
rpm-build c487f7
  if (!ostree_repo_read_commit (self->repo, self->last_parent, &current_root, NULL, NULL, error))
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  return get_changes (self, NULL, current_root, NULL, error);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_cache_disable_lookups (BuilderCache *self)
rpm-build c487f7
{
rpm-build c487f7
  self->disabled = TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
builder_gc (BuilderCache *self,
rpm-build c487f7
            gboolean      prune_unused_stages,
rpm-build c487f7
            GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  gint objects_total;
rpm-build c487f7
  gint objects_pruned;
rpm-build c487f7
  guint64 pruned_object_size_total;
rpm-build c487f7
  GHashTableIter iter;
rpm-build c487f7
  gpointer key, value;
rpm-build c487f7
rpm-build c487f7
  if (prune_unused_stages)
rpm-build c487f7
    {
rpm-build c487f7
      g_hash_table_iter_init (&iter, self->unused_stages);
rpm-build c487f7
      while (g_hash_table_iter_next (&iter, &key, &value))
rpm-build c487f7
        {
rpm-build c487f7
          const char *unused_stage = (const char *) key;
rpm-build c487f7
          g_autofree char *unused_ref = get_ref (self, unused_stage);
rpm-build c487f7
rpm-build c487f7
          g_debug ("Removing unused ref %s", unused_ref);
rpm-build c487f7
rpm-build c487f7
          if (!ostree_repo_set_ref_immediate (self->repo,
rpm-build c487f7
                                              NULL,
rpm-build c487f7
                                              unused_ref,
rpm-build c487f7
                                              NULL,
rpm-build c487f7
                                              NULL, error))
rpm-build c487f7
            return FALSE;
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  g_print ("Pruning cache\n");
rpm-build c487f7
  return ostree_repo_prune (self->repo,
rpm-build c487f7
                            OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY, -1,
rpm-build c487f7
                            &objects_total,
rpm-build c487f7
                            &objects_pruned,
rpm-build c487f7
                            &pruned_object_size_total,
rpm-build c487f7
                            NULL, error);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
/* Only add to cache if non-empty. This means we can add
rpm-build c487f7
   these things compatibly without invalidating the cache.
rpm-build c487f7
   This is useful if empty means no change from what was
rpm-build c487f7
   before */
rpm-build c487f7
void
rpm-build c487f7
builder_cache_checksum_compat_str (BuilderCache *self,
rpm-build c487f7
                                   const char   *str)
rpm-build c487f7
{
rpm-build c487f7
  if (str)
rpm-build c487f7
    builder_cache_checksum_str (self, str);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_cache_checksum_str (BuilderCache *self,
rpm-build c487f7
                            const char   *str)
rpm-build c487f7
{
rpm-build c487f7
  /* We include the terminating zero so that we make
rpm-build c487f7
   * a difference between NULL and "". */
rpm-build c487f7
rpm-build c487f7
  if (str)
rpm-build c487f7
    g_checksum_update (self->checksum, (const guchar *) str, strlen (str) + 1);
rpm-build c487f7
  else
rpm-build c487f7
    /* Always add something so we can't be fooled by a sequence like
rpm-build c487f7
       NULL, "a" turning into "a", NULL. */
rpm-build c487f7
    g_checksum_update (self->checksum, (const guchar *) "\1", 1);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
/* Only add to cache if non-empty. This means we can add
rpm-build c487f7
   these things compatibly without invalidating the cache.
rpm-build c487f7
   This is useful if empty means no change from what was
rpm-build c487f7
   before */
rpm-build c487f7
void
rpm-build c487f7
builder_cache_checksum_compat_strv (BuilderCache *self,
rpm-build c487f7
                                    char        **strv)
rpm-build c487f7
{
rpm-build c487f7
  if (strv != NULL && strv[0] != NULL)
rpm-build c487f7
    builder_cache_checksum_strv (self, strv);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_cache_checksum_strv (BuilderCache *self,
rpm-build c487f7
                             char        **strv)
rpm-build c487f7
{
rpm-build c487f7
  int i;
rpm-build c487f7
rpm-build c487f7
  if (strv)
rpm-build c487f7
    {
rpm-build c487f7
      g_checksum_update (self->checksum, (const guchar *) "\1", 1);
rpm-build c487f7
      for (i = 0; strv[i] != NULL; i++)
rpm-build c487f7
        builder_cache_checksum_str (self, strv[i]);
rpm-build c487f7
    }
rpm-build c487f7
  else
rpm-build c487f7
    {
rpm-build c487f7
      g_checksum_update (self->checksum, (const guchar *) "\2", 1);
rpm-build c487f7
    }
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_cache_checksum_boolean (BuilderCache *self,
rpm-build c487f7
                                gboolean      val)
rpm-build c487f7
{
rpm-build c487f7
  if (val)
rpm-build c487f7
    g_checksum_update (self->checksum, (const guchar *) "\1", 1);
rpm-build c487f7
  else
rpm-build c487f7
    g_checksum_update (self->checksum, (const guchar *) "\0", 1);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
/* Only add to cache if true. This means we can add
rpm-build c487f7
   these things compatibly without invalidating the cache.
rpm-build c487f7
   This is useful if false means no change from what was
rpm-build c487f7
   before */
rpm-build c487f7
void
rpm-build c487f7
builder_cache_checksum_compat_boolean (BuilderCache *self,
rpm-build c487f7
                                       gboolean      val)
rpm-build c487f7
{
rpm-build c487f7
  if (val)
rpm-build c487f7
    builder_cache_checksum_boolean (self, val);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_cache_checksum_uint32 (BuilderCache *self,
rpm-build c487f7
                               guint32       val)
rpm-build c487f7
{
rpm-build c487f7
  guchar v[4];
rpm-build c487f7
rpm-build c487f7
  v[0] = (val >> 0) & 0xff;
rpm-build c487f7
  v[1] = (val >> 8) & 0xff;
rpm-build c487f7
  v[2] = (val >> 16) & 0xff;
rpm-build c487f7
  v[3] = (val >> 24) & 0xff;
rpm-build c487f7
  g_checksum_update (self->checksum, v, 4);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_cache_checksum_random (BuilderCache *self)
rpm-build c487f7
{
rpm-build c487f7
  builder_cache_checksum_uint32 (self, g_random_int ());
rpm-build c487f7
  builder_cache_checksum_uint32 (self, g_random_int ());
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_cache_checksum_uint64 (BuilderCache *self,
rpm-build c487f7
                               guint64       val)
rpm-build c487f7
{
rpm-build c487f7
  guchar v[8];
rpm-build c487f7
rpm-build c487f7
  v[0] = (val >> 0) & 0xff;
rpm-build c487f7
  v[1] = (val >> 8) & 0xff;
rpm-build c487f7
  v[2] = (val >> 16) & 0xff;
rpm-build c487f7
  v[3] = (val >> 24) & 0xff;
rpm-build c487f7
  v[4] = (val >> 32) & 0xff;
rpm-build c487f7
  v[5] = (val >> 40) & 0xff;
rpm-build c487f7
  v[6] = (val >> 48) & 0xff;
rpm-build c487f7
  v[7] = (val >> 56) & 0xff;
rpm-build c487f7
rpm-build c487f7
  g_checksum_update (self->checksum, v, 8);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_cache_checksum_data (BuilderCache *self,
rpm-build c487f7
                             guint8       *data,
rpm-build c487f7
                             gsize         len)
rpm-build c487f7
{
rpm-build c487f7
  g_checksum_update (self->checksum, data, len);
rpm-build c487f7
}