Пример #1
0
/**
 * rpmostreed_repo_lookup_checksum:
 * @repo: Repo
 * @refspec: Repository branch
 * @checksum: Checksum to look for
 * @progress: (allow-none): Progress
 * @cancellable: Cancellable
 * @error: Error
 *
 * Tries to determine if the checksum given belongs on the remote and branch
 * given by @refspec. This may require pulling commit objects from a remote
 * repository.
 *
 * Returns: %TRUE on success, %FALSE on failure
 */
gboolean
rpmostreed_repo_lookup_checksum (OstreeRepo           *repo,
                                 const char           *refspec,
                                 const char           *checksum,
                                 OstreeAsyncProgress  *progress,
                                 GCancellable         *cancellable,
                                 GError              **error)
{
  ChecksumVisitorClosure closure = { checksum, FALSE };

  g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE);
  g_return_val_if_fail (refspec != NULL, FALSE);
  g_return_val_if_fail (checksum != NULL, FALSE);

  if (!rpmostreed_repo_pull_ancestry (repo, refspec,
                                      checksum_visitor, &closure,
                                      progress, cancellable, error))
    return FALSE;

  if (!closure.found)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
                   "Checksum %s not found in %s", checksum, refspec);
      return FALSE;
    }

  return TRUE;
}
Пример #2
0
/**
 * rpmostreed_repo_lookup_cached_version:
 * @repo: Repo
 * @refspec: Repository branch
 * @version: Version to look for
 * @cancellable: Cancellable
 * @out_checksum: (out) (allow-none): Commit checksum, or %NULL
 * @error: Error
 *
 * Similar to rpmostreed_repo_lookup_version(), except without pulling
 * from a remote repository.  It traverses whatever commits are available
 * locally in @repo.
 *
 * Returns: %TRUE on success, %FALSE on failure
 */
gboolean
rpmostreed_repo_lookup_cached_version (OstreeRepo    *repo,
                                       const char    *refspec,
                                       const char    *version,
                                       GCancellable  *cancellable,
                                       char         **out_checksum,
                                       GError       **error)
{
  VersionVisitorClosure closure = { version, NULL };
  g_autofree char *checksum = NULL;
  gboolean ret = FALSE;

  g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE);
  g_return_val_if_fail (refspec != NULL, FALSE);
  g_return_val_if_fail (version != NULL, FALSE);

  if (!ostree_repo_resolve_rev (repo, refspec, FALSE, &checksum, error))
    goto out;

  while (checksum != NULL)
    {
      g_autoptr(GVariant) commit = NULL;
      gboolean stop = FALSE;

      if (!ostree_repo_load_commit (repo, checksum, &commit, NULL, error))
        goto out;

      if (!version_visitor (repo, checksum, commit, &closure, &stop, error))
        goto out;

      g_clear_pointer (&checksum, g_free);

      if (!stop)
        checksum = ostree_commit_get_parent (commit);
    }

  if (closure.checksum == NULL)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
                   "Version %s not cached in %s", version, refspec);
      goto out;
    }

  if (out_checksum != NULL)
    *out_checksum = g_steal_pointer (&closure.checksum);

  g_free (closure.checksum);

  ret = TRUE;

out:
  return ret;
}
Пример #3
0
gboolean
is_checksum_an_update (OstreeRepo *repo,
                       const gchar *checksum,
                       GVariant **commit,
                       GError **error)
{
  g_autofree gchar *cur = NULL;
  g_autoptr(GVariant) current_commit = NULL;
  g_autoptr(GVariant) update_commit = NULL;
  gboolean is_newer;
  guint64 update_timestamp, current_timestamp;

  g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE);
  g_return_val_if_fail (checksum != NULL, FALSE);
  g_return_val_if_fail (commit != NULL, FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  cur = eos_updater_get_booted_checksum (error);
  if (cur == NULL)
    return FALSE;

  g_debug ("%s: current: %s, update: %s", G_STRFUNC, cur, checksum);

  if (!ostree_repo_load_commit (repo, cur, &current_commit, NULL, error))
    return FALSE;

  if (!ostree_repo_load_commit (repo, checksum, &update_commit, NULL, error))
    return FALSE;

  /* Determine if the new commit is newer than the old commit to prevent
   * inadvertent (or malicious) attempts to downgrade the system.
   */
  update_timestamp = ostree_commit_get_timestamp (update_commit);
  current_timestamp = ostree_commit_get_timestamp (current_commit);

  g_debug ("%s: current_timestamp: %" G_GUINT64_FORMAT ", "
           "update_timestamp: %" G_GUINT64_FORMAT,
           G_STRFUNC, update_timestamp, current_timestamp);

  is_newer = update_timestamp > current_timestamp;
  /* if we have a checksum for the remote upgrade candidate
   * and it's ≠ what we're currently booted into, advertise it as such.
   */
  if (is_newer && g_strcmp0 (cur, checksum) != 0)
    *commit = g_steal_pointer (&update_commit);
  else
    *commit = NULL;

  return TRUE;
}
Пример #4
0
gboolean
fetch_latest_commit (OstreeRepo *repo,
                     GCancellable *cancellable,
                     const gchar *remote_name,
                     const gchar *ref,
                     const gchar *url_override,
                     gchar **out_checksum,
                     EosExtensions **out_extensions,
                     GError **error)
{
  g_autoptr(GBytes) summary_bytes = NULL;
  g_autoptr(GVariant) summary = NULL;
  g_autofree gchar *checksum = NULL;
  g_autoptr(GVariant) options = NULL;

  g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE);
  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
  g_return_val_if_fail (remote_name != NULL, FALSE);
  g_return_val_if_fail (ref != NULL, FALSE);
  g_return_val_if_fail (out_checksum != NULL, FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  options = get_repo_pull_options (url_override, ref);
  if (!ostree_repo_pull_with_options (repo,
                                      remote_name,
                                      options,
                                      NULL,
                                      cancellable,
                                      error))
    return FALSE;

  return fetch_commit_checksum (repo,
                                cancellable,
                                remote_name,
                                ref,
                                url_override,
                                out_checksum,
                                out_extensions,
                                error);
}
Пример #5
0
/**
 * rpmostreed_repo_lookup_version:
 * @repo: Repo
 * @refspec: Repository branch
 * @version: Version to look for
 * @progress: (allow-none): Progress
 * @cancellable: Cancellable
 * @out_checksum: (out) (allow-none): Commit checksum, or %NULL
 * @error: Error
 *
 * Tries to determine the commit checksum for @version on @refspec.
 * This may require pulling commit objects from a remote repository.
 *
 * Returns: %TRUE on success, %FALSE on failure
 */
gboolean
rpmostreed_repo_lookup_version (OstreeRepo           *repo,
                                const char           *refspec,
                                const char           *version,
                                OstreeAsyncProgress  *progress,
                                GCancellable         *cancellable,
                                char                **out_checksum,
                                GError              **error)
{
  VersionVisitorClosure closure = { version, NULL };
  gboolean ret = FALSE;

  g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE);
  g_return_val_if_fail (refspec != NULL, FALSE);
  g_return_val_if_fail (version != NULL, FALSE);

  if (!rpmostreed_repo_pull_ancestry (repo, refspec,
                                      version_visitor, &closure,
                                      progress, cancellable, error))
    goto out;

  if (closure.checksum == NULL)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
                   "Version %s not found in %s", version, refspec);
      goto out;
    }

  if (out_checksum != NULL)
    *out_checksum = g_steal_pointer (&closure.checksum);

  g_free (closure.checksum);

  ret = TRUE;

out:
  return ret;
}
Пример #6
0
/**
 * rpmostreed_repo_pull_ancestry:
 * @repo: Repo
 * @refspec: Repository branch
 * @visitor: (allow-none): Visitor function to call on each commit
 * @visitor_data: (allow-none): User data for @visitor
 * @progress: (allow-none): Progress
 * @cancellable: Cancellable
 * @error: Error
 *
 * Downloads an ancestry of commit objects starting from @refspec.
 *
 * If a @visitor function pointer is given, commit objects are downloaded
 * in batches and the @visitor function is called for each commit object.
 * The @visitor function can stop the recursion, such as when looking for
 * a particular commit.
 *
 * Returns: %TRUE on success, %FALSE on failure
 */
gboolean
rpmostreed_repo_pull_ancestry (OstreeRepo               *repo,
                               const char               *refspec,
                               RpmostreedCommitVisitor   visitor,
                               gpointer                  visitor_data,
                               OstreeAsyncProgress      *progress,
                               GCancellable             *cancellable,
                               GError                  **error)
{
  OstreeRepoPullFlags flags;
  GVariantDict options;
  GVariant *refs_value;
  const char *refs_array[] = { NULL, NULL };
  g_autofree char *remote = NULL;
  g_autofree char *ref = NULL;
  g_autofree char *checksum = NULL;
  int depth, ii;
  gboolean ret = FALSE;

  g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE);
  g_return_val_if_fail (refspec != NULL, FALSE);

  if (!ostree_parse_refspec (refspec, &remote, &ref, error))
    goto out;

  /* If no visitor function was provided then we won't be short-circuiting
   * the recursion, so pull everything in one shot. Otherwise pull commits
   * in increasingly large batches. */
  depth = (visitor != NULL) ? 10 : -1;

  flags = OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY;

  /* It's important to use the ref name instead of a checksum on the first
   * pass because we want to search from the latest available commit on the
   * remote server, which is not necessarily what the ref name is currently
   * pointing at in our local repo. */
  refs_array[0] = ref;

  while (TRUE)
    {
      /* Floating reference, transferred to dictionary. */
      refs_value = g_variant_new_strv ((const char * const *) refs_array, -1);

      g_variant_dict_init (&options, NULL);
      g_variant_dict_insert (&options, "depth", "i", depth);
      g_variant_dict_insert (&options, "flags", "i", flags);
      g_variant_dict_insert_value (&options, "refs", refs_value);

      if (!ostree_repo_pull_with_options (repo, remote,
                                          g_variant_dict_end (&options),
                                          progress, cancellable, error))
        goto out;

      /* First pass only.  Now we can resolve the ref to a checksum. */
      if (checksum == NULL)
        {
          if (!ostree_repo_resolve_rev (repo, ref, FALSE, &checksum, error))
            goto out;
        }

      /* If depth is negative (no visitor), this loop is skipped. */
      for (ii = 0; ii < depth && checksum != NULL; ii++)
        {
          g_autoptr(GVariant) commit = NULL;
          gboolean stop = FALSE;

          if (!ostree_repo_load_commit (repo, checksum, &commit, NULL, error))
            goto out;

          if (!visitor (repo, checksum, commit, visitor_data, &stop, error))
            goto out;

          g_clear_pointer (&checksum, g_free);

          if (!stop)
            checksum = ostree_commit_get_parent (commit);
        }

      /* Break if no visitor, or visitor told us to stop. */
      if (depth < 0 || checksum == NULL)
        break;

      /* Pull the next batch of commits, twice as many. */
      refs_array[0] = checksum;
      depth = depth * 2;
    }

  ret = TRUE;

out:
  return ret;
}