From cb6b69616c7e452599b9e49edf73fcd893fb887e Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 9 Jul 2013 19:49:00 -0400 Subject: [PATCH] libostree: Split off -refs.c Continuing to break up ostree-repo.c. --- Makefile-libostree.am | 1 + src/libostree/ostree-repo-refs.c | 670 +++++++++++++++++++++++++++++++ src/libostree/ostree-repo.c | 646 ----------------------------- 3 files changed, 671 insertions(+), 646 deletions(-) create mode 100644 src/libostree/ostree-repo-refs.c diff --git a/Makefile-libostree.am b/Makefile-libostree.am index cbe3bb9e..1ad3b634 100644 --- a/Makefile-libostree.am +++ b/Makefile-libostree.am @@ -33,6 +33,7 @@ libostree_la_SOURCES = src/libostree/ostree.h \ src/libostree/ostree-repo.c \ src/libostree/ostree-repo-checkout.c \ src/libostree/ostree-repo-libarchive.c \ + src/libostree/ostree-repo-refs.c \ src/libostree/ostree-repo.h \ src/libostree/ostree-repo-private.h \ src/libostree/ostree-repo-file.c \ diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c new file mode 100644 index 00000000..fb9f3618 --- /dev/null +++ b/src/libostree/ostree-repo-refs.c @@ -0,0 +1,670 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2011 Colin Walters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ostree-repo-private.h" + +static gboolean +add_ref_to_set (const char *remote, + GFile *base, + GFile *child, + GHashTable *refs, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + char *contents; + char *relpath; + gsize len; + GString *refname; + + if (!g_file_load_contents (child, cancellable, &contents, &len, NULL, error)) + goto out; + + g_strchomp (contents); + + refname = g_string_new (""); + if (remote) + { + g_string_append (refname, remote); + g_string_append_c (refname, ':'); + } + relpath = g_file_get_relative_path (base, child); + g_string_append (refname, relpath); + g_free (relpath); + + g_hash_table_insert (refs, g_string_free (refname, FALSE), contents); + + ret = TRUE; + out: + return ret; +} + +static gboolean +write_checksum_file (GFile *parentdir, + const char *name, + const char *sha256, + GError **error) +{ + gboolean ret = FALSE; + gsize bytes_written; + int i; + gs_unref_object GFile *parent = NULL; + gs_unref_object GFile *child = NULL; + gs_unref_object GOutputStream *out = NULL; + gs_unref_ptrarray GPtrArray *components = NULL; + + if (!ostree_validate_checksum_string (sha256, error)) + goto out; + + if (ostree_validate_checksum_string (name, NULL)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Rev name '%s' looks like a checksum", name); + goto out; + } + + if (!ot_util_path_split_validate (name, &components, error)) + goto out; + + if (components->len == 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid empty ref name"); + goto out; + } + + parent = g_object_ref (parentdir); + for (i = 0; i+1 < components->len; i++) + { + child = g_file_get_child (parent, (char*)components->pdata[i]); + + if (!gs_file_ensure_directory (child, FALSE, NULL, error)) + goto out; + + g_clear_object (&parent); + parent = child; + child = NULL; + } + + child = g_file_get_child (parent, components->pdata[components->len - 1]); + if ((out = (GOutputStream*)g_file_replace (child, NULL, FALSE, 0, NULL, error)) == NULL) + goto out; + if (!g_output_stream_write_all (out, sha256, strlen (sha256), &bytes_written, NULL, error)) + goto out; + if (!g_output_stream_write_all (out, "\n", 1, &bytes_written, NULL, error)) + goto out; + if (!g_output_stream_close (out, NULL, error)) + goto out; + + ret = TRUE; + out: + return ret; +} + + +static gboolean +parse_rev_file (OstreeRepo *self, + GFile *f, + char **sha256, + GError **error) G_GNUC_UNUSED; + +static gboolean +parse_rev_file (OstreeRepo *self, + GFile *f, + char **sha256, + GError **error) +{ + gboolean ret = FALSE; + GError *temp_error = NULL; + gs_free char *rev = NULL; + + if ((rev = gs_file_load_contents_utf8 (f, NULL, &temp_error)) == NULL) + goto out; + + if (rev == NULL) + { + if (g_error_matches (temp_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) + { + g_clear_error (&temp_error); + } + else + { + g_propagate_error (error, temp_error); + goto out; + } + } + else + { + g_strchomp (rev); + } + + if (g_str_has_prefix (rev, "ref: ")) + { + gs_unref_object GFile *ref = NULL; + char *ref_sha256; + gboolean subret; + + ref = g_file_resolve_relative_path (self->local_heads_dir, rev + 5); + subret = parse_rev_file (self, ref, &ref_sha256, error); + + if (!subret) + { + g_free (ref_sha256); + goto out; + } + + g_free (rev); + rev = ref_sha256; + } + else + { + if (!ostree_validate_checksum_string (rev, error)) + goto out; + } + + ot_transfer_out_value(sha256, &rev); + ret = TRUE; + out: + return ret; +} + +static gboolean +find_ref_in_remotes (OstreeRepo *self, + const char *rev, + GFile **out_file, + GError **error) +{ + gboolean ret = FALSE; + gs_unref_object GFileEnumerator *dir_enum = NULL; + gs_unref_object GFile *ret_file = NULL; + + dir_enum = g_file_enumerate_children (self->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, error); + if (!dir_enum) + goto out; + + while (TRUE) + { + GFileInfo *file_info; + GFile *child; + if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child, + NULL, error)) + goto out; + if (file_info == NULL) + break; + if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) + continue; + + g_clear_object (&ret_file); + ret_file = g_file_resolve_relative_path (child, rev); + if (!g_file_query_exists (ret_file, NULL)) + g_clear_object (&ret_file); + else + break; + } + + ret = TRUE; + ot_transfer_out_value (out_file, &ret_file); + out: + return ret; +} + +static gboolean +resolve_refspec (OstreeRepo *self, + const char *remote, + const char *ref, + gboolean allow_noent, + char **out_rev, + GError **error); + +static gboolean +resolve_refspec_fallback (OstreeRepo *self, + const char *remote, + const char *ref, + gboolean allow_noent, + char **out_rev, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + gs_free char *ret_rev = NULL; + + if (self->parent_repo) + { + if (!resolve_refspec (self->parent_repo, remote, ref, + allow_noent, &ret_rev, error)) + goto out; + } + else if (!allow_noent) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Refspec '%s%s%s' not found", + remote ? remote : "", + remote ? ":" : "", + ref); + goto out; + } + + ret = TRUE; + ot_transfer_out_value (out_rev, &ret_rev); + out: + return ret; +} + +static gboolean +resolve_refspec (OstreeRepo *self, + const char *remote, + const char *ref, + gboolean allow_noent, + char **out_rev, + GError **error) +{ + gboolean ret = FALSE; + __attribute__((unused)) GCancellable *cancellable = NULL; + GError *temp_error = NULL; + gs_free char *tmp = NULL; + gs_free char *tmp2 = NULL; + gs_free char *ret_rev = NULL; + gs_unref_object GFile *child = NULL; + gs_unref_object GFile *origindir = NULL; + + g_return_val_if_fail (ref != NULL, FALSE); + + /* We intentionally don't allow a ref that looks like a checksum */ + if (ostree_validate_checksum_string (ref, NULL)) + { + ret_rev = g_strdup (ref); + } + else if (remote != NULL) + { + child = ot_gfile_resolve_path_printf (self->remote_heads_dir, "%s/%s", + remote, ref); + if (!g_file_query_exists (child, NULL)) + g_clear_object (&child); + } + else + { + child = g_file_resolve_relative_path (self->local_heads_dir, ref); + + if (!g_file_query_exists (child, NULL)) + { + g_clear_object (&child); + + child = g_file_resolve_relative_path (self->remote_heads_dir, ref); + + if (!g_file_query_exists (child, NULL)) + { + g_clear_object (&child); + + if (!find_ref_in_remotes (self, ref, &child, error)) + goto out; + } + } + } + + if (child) + { + if ((ret_rev = gs_file_load_contents_utf8 (child, NULL, &temp_error)) == NULL) + { + g_propagate_error (error, temp_error); + g_prefix_error (error, "Couldn't open ref '%s': ", gs_file_get_path_cached (child)); + goto out; + } + + g_strchomp (ret_rev); + if (!ostree_validate_checksum_string (ret_rev, error)) + goto out; + } + else + { + if (!resolve_refspec_fallback (self, remote, ref, allow_noent, + &ret_rev, cancellable, error)) + goto out; + } + + ot_transfer_out_value (out_rev, &ret_rev); + ret = TRUE; + out: + return ret; +} + +gboolean +ostree_repo_resolve_rev (OstreeRepo *self, + const char *refspec, + gboolean allow_noent, + char **out_rev, + GError **error) +{ + gboolean ret = FALSE; + gs_free char *ret_rev = NULL; + + g_return_val_if_fail (refspec != NULL, FALSE); + + if (ostree_validate_checksum_string (refspec, NULL)) + { + ret_rev = g_strdup (refspec); + } + else + { + if (g_str_has_suffix (refspec, "^")) + { + gs_free char *parent_refspec = NULL; + gs_free char *parent_rev = NULL; + gs_unref_variant GVariant *commit = NULL; + gs_unref_variant GVariant *parent_csum_v = NULL; + + parent_refspec = g_strdup (refspec); + parent_refspec[strlen(parent_refspec) - 1] = '\0'; + + if (!ostree_repo_resolve_rev (self, parent_refspec, allow_noent, &parent_rev, error)) + goto out; + + if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, parent_rev, + &commit, error)) + goto out; + + g_variant_get_child (commit, 1, "@ay", &parent_csum_v); + if (g_variant_n_children (parent_csum_v) == 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Commit %s has no parent", parent_rev); + goto out; + } + ret_rev = ostree_checksum_from_bytes_v (parent_csum_v); + } + else + { + gs_free char *remote = NULL; + gs_free char *ref = NULL; + + if (!ostree_parse_refspec (refspec, &remote, &ref, error)) + goto out; + + if (!resolve_refspec (self, remote, ref, allow_noent, + &ret_rev, error)) + goto out; + } + } + + ret = TRUE; + ot_transfer_out_value (out_rev, &ret_rev); + out: + return ret; +} + +static gboolean +enumerate_refs_recurse (OstreeRepo *repo, + const char *remote, + GFile *base, + GFile *dir, + GHashTable *refs, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + gs_unref_object GFileEnumerator *enumerator = NULL; + + enumerator = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!enumerator) + goto out; + + while (TRUE) + { + GFileInfo *file_info = NULL; + GFile *child = NULL; + + if (!gs_file_enumerator_iterate (enumerator, &file_info, &child, + NULL, error)) + goto out; + if (file_info == NULL) + break; + + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) + { + if (!enumerate_refs_recurse (repo, remote, base, child, refs, cancellable, error)) + goto out; + } + else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) + { + if (!add_ref_to_set (remote, base, child, refs, + cancellable, error)) + goto out; + } + } + + ret = TRUE; + out: + return ret; +} + +gboolean +ostree_repo_list_refs (OstreeRepo *repo, + const char *refspec_prefix, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + gs_unref_hashtable GHashTable *ret_all_refs = NULL; + gs_free char *remote = NULL; + gs_free char *ref_prefix = NULL; + + ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + if (refspec_prefix) + { + gs_unref_object GFile *dir = NULL; + gs_unref_object GFile *child = NULL; + gs_unref_object GFileInfo *info = NULL; + + if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error)) + goto out; + + if (remote) + dir = g_file_get_child (repo->remote_heads_dir, remote); + else + dir = g_object_ref (repo->local_heads_dir); + + child = g_file_resolve_relative_path (dir, ref_prefix); + if (!ot_gfile_query_info_allow_noent (child, OSTREE_GIO_FAST_QUERYINFO, 0, + &info, cancellable, error)) + goto out; + + if (info) + { + if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) + { + if (!enumerate_refs_recurse (repo, remote, child, child, + ret_all_refs, + cancellable, error)) + goto out; + } + else + { + if (!add_ref_to_set (remote, dir, child, ret_all_refs, + cancellable, error)) + goto out; + } + } + } + else + { + gs_unref_object GFileEnumerator *remote_enumerator = NULL; + + if (!enumerate_refs_recurse (repo, NULL, repo->local_heads_dir, repo->local_heads_dir, + ret_all_refs, + cancellable, error)) + goto out; + + remote_enumerator = g_file_enumerate_children (repo->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO, + 0, + cancellable, error); + + while (TRUE) + { + GFileInfo *info; + GFile *child; + const char *name; + + if (!gs_file_enumerator_iterate (remote_enumerator, &info, &child, + cancellable, error)) + goto out; + if (!info) + break; + + name = g_file_info_get_name (info); + if (!enumerate_refs_recurse (repo, name, child, child, + ret_all_refs, + cancellable, error)) + goto out; + } + } + + ret = TRUE; + ot_transfer_out_value (out_all_refs, &ret_all_refs); + out: + return ret; +} + +static gboolean +write_ref_summary (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + GHashTableIter hash_iter; + gpointer key, value; + gsize bytes_written; + gs_unref_hashtable GHashTable *all_refs = NULL; + gs_unref_object GFile *summary_path = NULL; + gs_unref_object GOutputStream *out = NULL; + gs_free char *buf = NULL; + + if (!ostree_repo_list_refs (self, NULL, &all_refs, cancellable, error)) + goto out; + + summary_path = g_file_resolve_relative_path (ostree_repo_get_path (self), + "refs/summary"); + + out = (GOutputStream*) g_file_replace (summary_path, NULL, FALSE, 0, cancellable, error); + if (!out) + goto out; + + g_hash_table_iter_init (&hash_iter, all_refs); + while (g_hash_table_iter_next (&hash_iter, &key, &value)) + { + const char *name = key; + const char *sha256 = value; + + g_free (buf); + buf = g_strdup_printf ("%s %s\n", sha256, name); + if (!g_output_stream_write_all (out, buf, strlen (buf), &bytes_written, cancellable, error)) + goto out; + } + + if (!g_output_stream_close (out, cancellable, error)) + goto out; + + ret = TRUE; + out: + return ret; +} + +gboolean +ostree_repo_write_ref (OstreeRepo *self, + const char *remote, + const char *name, + const char *rev, + GError **error) +{ + gboolean ret = FALSE; + gs_unref_object GFile *dir = NULL; + + if (remote == NULL) + dir = g_object_ref (self->local_heads_dir); + else + { + dir = g_file_get_child (self->remote_heads_dir, remote); + + if (rev != NULL) + { + if (!gs_file_ensure_directory (dir, FALSE, NULL, error)) + goto out; + } + } + + if (rev == NULL) + { + gs_unref_object GFile *child = g_file_resolve_relative_path (dir, name); + + if (g_file_query_exists (child, NULL)) + { + if (!gs_file_unlink (child, NULL, error)) + goto out; + } + } + else + { + if (!write_checksum_file (dir, name, rev, error)) + goto out; + + if (rev != NULL) + { + if (self->mode == OSTREE_REPO_MODE_ARCHIVE + || self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2) + { + if (!write_ref_summary (self, NULL, error)) + goto out; + } + } + } + + ret = TRUE; + out: + return ret; +} + +gboolean +ostree_repo_write_refspec (OstreeRepo *self, + const char *refspec, + const char *rev, + GError **error) +{ + gboolean ret = FALSE; + gs_free char *remote = NULL; + gs_free char *ref = NULL; + + if (!ostree_parse_refspec (refspec, &remote, &ref, error)) + goto out; + + if (!ostree_repo_write_ref (self, remote, ref, rev, error)) + goto out; + + ret = TRUE; + out: + return ret; +} diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 2b9ba65b..a151b713 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -186,361 +186,6 @@ ostree_repo_new (GFile *path) { return g_object_new (OSTREE_TYPE_REPO, "path", path, NULL); } - -static gboolean -parse_rev_file (OstreeRepo *self, - GFile *f, - char **sha256, - GError **error) G_GNUC_UNUSED; - -static gboolean -parse_rev_file (OstreeRepo *self, - GFile *f, - char **sha256, - GError **error) -{ - gboolean ret = FALSE; - GError *temp_error = NULL; - gs_free char *rev = NULL; - - if ((rev = gs_file_load_contents_utf8 (f, NULL, &temp_error)) == NULL) - goto out; - - if (rev == NULL) - { - if (g_error_matches (temp_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) - { - g_clear_error (&temp_error); - } - else - { - g_propagate_error (error, temp_error); - goto out; - } - } - else - { - g_strchomp (rev); - } - - if (g_str_has_prefix (rev, "ref: ")) - { - gs_unref_object GFile *ref = NULL; - char *ref_sha256; - gboolean subret; - - ref = g_file_resolve_relative_path (self->local_heads_dir, rev + 5); - subret = parse_rev_file (self, ref, &ref_sha256, error); - - if (!subret) - { - g_free (ref_sha256); - goto out; - } - - g_free (rev); - rev = ref_sha256; - } - else - { - if (!ostree_validate_checksum_string (rev, error)) - goto out; - } - - ot_transfer_out_value(sha256, &rev); - ret = TRUE; - out: - return ret; -} - -static gboolean -find_ref_in_remotes (OstreeRepo *self, - const char *rev, - GFile **out_file, - GError **error) -{ - gboolean ret = FALSE; - gs_unref_object GFileEnumerator *dir_enum = NULL; - gs_unref_object GFile *ret_file = NULL; - - dir_enum = g_file_enumerate_children (self->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, error); - if (!dir_enum) - goto out; - - while (TRUE) - { - GFileInfo *file_info; - GFile *child; - if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child, - NULL, error)) - goto out; - if (file_info == NULL) - break; - if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) - continue; - - g_clear_object (&ret_file); - ret_file = g_file_resolve_relative_path (child, rev); - if (!g_file_query_exists (ret_file, NULL)) - g_clear_object (&ret_file); - else - break; - } - - ret = TRUE; - ot_transfer_out_value (out_file, &ret_file); - out: - return ret; -} - -static gboolean -resolve_refspec (OstreeRepo *self, - const char *remote, - const char *ref, - gboolean allow_noent, - char **out_rev, - GError **error); - -static gboolean -resolve_refspec_fallback (OstreeRepo *self, - const char *remote, - const char *ref, - gboolean allow_noent, - char **out_rev, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - gs_free char *ret_rev = NULL; - - if (self->parent_repo) - { - if (!resolve_refspec (self->parent_repo, remote, ref, - allow_noent, &ret_rev, error)) - goto out; - } - else if (!allow_noent) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Refspec '%s%s%s' not found", - remote ? remote : "", - remote ? ":" : "", - ref); - goto out; - } - - ret = TRUE; - ot_transfer_out_value (out_rev, &ret_rev); - out: - return ret; -} - -static gboolean -resolve_refspec (OstreeRepo *self, - const char *remote, - const char *ref, - gboolean allow_noent, - char **out_rev, - GError **error) -{ - gboolean ret = FALSE; - __attribute__((unused)) GCancellable *cancellable = NULL; - GError *temp_error = NULL; - gs_free char *tmp = NULL; - gs_free char *tmp2 = NULL; - gs_free char *ret_rev = NULL; - gs_unref_object GFile *child = NULL; - gs_unref_object GFile *origindir = NULL; - - g_return_val_if_fail (ref != NULL, FALSE); - - /* We intentionally don't allow a ref that looks like a checksum */ - if (ostree_validate_checksum_string (ref, NULL)) - { - ret_rev = g_strdup (ref); - } - else if (remote != NULL) - { - child = ot_gfile_resolve_path_printf (self->remote_heads_dir, "%s/%s", - remote, ref); - if (!g_file_query_exists (child, NULL)) - g_clear_object (&child); - } - else - { - child = g_file_resolve_relative_path (self->local_heads_dir, ref); - - if (!g_file_query_exists (child, NULL)) - { - g_clear_object (&child); - - child = g_file_resolve_relative_path (self->remote_heads_dir, ref); - - if (!g_file_query_exists (child, NULL)) - { - g_clear_object (&child); - - if (!find_ref_in_remotes (self, ref, &child, error)) - goto out; - } - } - } - - if (child) - { - if ((ret_rev = gs_file_load_contents_utf8 (child, NULL, &temp_error)) == NULL) - { - g_propagate_error (error, temp_error); - g_prefix_error (error, "Couldn't open ref '%s': ", gs_file_get_path_cached (child)); - goto out; - } - - g_strchomp (ret_rev); - if (!ostree_validate_checksum_string (ret_rev, error)) - goto out; - } - else - { - if (!resolve_refspec_fallback (self, remote, ref, allow_noent, - &ret_rev, cancellable, error)) - goto out; - } - - ot_transfer_out_value (out_rev, &ret_rev); - ret = TRUE; - out: - return ret; -} - -gboolean -ostree_repo_resolve_rev (OstreeRepo *self, - const char *refspec, - gboolean allow_noent, - char **out_rev, - GError **error) -{ - gboolean ret = FALSE; - gs_free char *ret_rev = NULL; - - g_return_val_if_fail (refspec != NULL, FALSE); - - if (ostree_validate_checksum_string (refspec, NULL)) - { - ret_rev = g_strdup (refspec); - } - else - { - if (g_str_has_suffix (refspec, "^")) - { - gs_free char *parent_refspec = NULL; - gs_free char *parent_rev = NULL; - gs_unref_variant GVariant *commit = NULL; - gs_unref_variant GVariant *parent_csum_v = NULL; - - parent_refspec = g_strdup (refspec); - parent_refspec[strlen(parent_refspec) - 1] = '\0'; - - if (!ostree_repo_resolve_rev (self, parent_refspec, allow_noent, &parent_rev, error)) - goto out; - - if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, parent_rev, - &commit, error)) - goto out; - - g_variant_get_child (commit, 1, "@ay", &parent_csum_v); - if (g_variant_n_children (parent_csum_v) == 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Commit %s has no parent", parent_rev); - goto out; - } - ret_rev = ostree_checksum_from_bytes_v (parent_csum_v); - } - else - { - gs_free char *remote = NULL; - gs_free char *ref = NULL; - - if (!ostree_parse_refspec (refspec, &remote, &ref, error)) - goto out; - - if (!resolve_refspec (self, remote, ref, allow_noent, - &ret_rev, error)) - goto out; - } - } - - ret = TRUE; - ot_transfer_out_value (out_rev, &ret_rev); - out: - return ret; -} - - -static gboolean -write_checksum_file (GFile *parentdir, - const char *name, - const char *sha256, - GError **error) -{ - gboolean ret = FALSE; - gsize bytes_written; - int i; - gs_unref_object GFile *parent = NULL; - gs_unref_object GFile *child = NULL; - gs_unref_object GOutputStream *out = NULL; - gs_unref_ptrarray GPtrArray *components = NULL; - - if (!ostree_validate_checksum_string (sha256, error)) - goto out; - - if (ostree_validate_checksum_string (name, NULL)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Rev name '%s' looks like a checksum", name); - goto out; - } - - if (!ot_util_path_split_validate (name, &components, error)) - goto out; - - if (components->len == 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid empty ref name"); - goto out; - } - - parent = g_object_ref (parentdir); - for (i = 0; i+1 < components->len; i++) - { - child = g_file_get_child (parent, (char*)components->pdata[i]); - - if (!gs_file_ensure_directory (child, FALSE, NULL, error)) - goto out; - - g_clear_object (&parent); - parent = child; - child = NULL; - } - - child = g_file_get_child (parent, components->pdata[components->len - 1]); - if ((out = (GOutputStream*)g_file_replace (child, NULL, FALSE, 0, NULL, error)) == NULL) - goto out; - if (!g_output_stream_write_all (out, sha256, strlen (sha256), &bytes_written, NULL, error)) - goto out; - if (!g_output_stream_write_all (out, "\n", 1, &bytes_written, NULL, error)) - goto out; - if (!g_output_stream_close (out, NULL, error)) - goto out; - - ret = TRUE; - out: - return ret; -} - /** * ostree_repo_get_config: * @self: @@ -1752,297 +1397,6 @@ create_empty_gvariant_dict (void) return g_variant_builder_end (&builder); } -static gboolean -add_ref_to_set (const char *remote, - GFile *base, - GFile *child, - GHashTable *refs, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - char *contents; - char *relpath; - gsize len; - GString *refname; - - if (!g_file_load_contents (child, cancellable, &contents, &len, NULL, error)) - goto out; - - g_strchomp (contents); - - refname = g_string_new (""); - if (remote) - { - g_string_append (refname, remote); - g_string_append_c (refname, ':'); - } - relpath = g_file_get_relative_path (base, child); - g_string_append (refname, relpath); - g_free (relpath); - - g_hash_table_insert (refs, g_string_free (refname, FALSE), contents); - - ret = TRUE; - out: - return ret; -} - -static gboolean -enumerate_refs_recurse (OstreeRepo *repo, - const char *remote, - GFile *base, - GFile *dir, - GHashTable *refs, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - gs_unref_object GFileEnumerator *enumerator = NULL; - - enumerator = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - cancellable, error); - if (!enumerator) - goto out; - - while (TRUE) - { - GFileInfo *file_info = NULL; - GFile *child = NULL; - - if (!gs_file_enumerator_iterate (enumerator, &file_info, &child, - NULL, error)) - goto out; - if (file_info == NULL) - break; - - if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) - { - if (!enumerate_refs_recurse (repo, remote, base, child, refs, cancellable, error)) - goto out; - } - else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) - { - if (!add_ref_to_set (remote, base, child, refs, - cancellable, error)) - goto out; - } - } - - ret = TRUE; - out: - return ret; -} - -gboolean -ostree_repo_list_refs (OstreeRepo *repo, - const char *refspec_prefix, - GHashTable **out_all_refs, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - gs_unref_hashtable GHashTable *ret_all_refs = NULL; - gs_free char *remote = NULL; - gs_free char *ref_prefix = NULL; - - ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - - if (refspec_prefix) - { - gs_unref_object GFile *dir = NULL; - gs_unref_object GFile *child = NULL; - gs_unref_object GFileInfo *info = NULL; - - if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error)) - goto out; - - if (remote) - dir = g_file_get_child (repo->remote_heads_dir, remote); - else - dir = g_object_ref (repo->local_heads_dir); - - child = g_file_resolve_relative_path (dir, ref_prefix); - if (!ot_gfile_query_info_allow_noent (child, OSTREE_GIO_FAST_QUERYINFO, 0, - &info, cancellable, error)) - goto out; - - if (info) - { - if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) - { - if (!enumerate_refs_recurse (repo, remote, child, child, - ret_all_refs, - cancellable, error)) - goto out; - } - else - { - if (!add_ref_to_set (remote, dir, child, ret_all_refs, - cancellable, error)) - goto out; - } - } - } - else - { - gs_unref_object GFileEnumerator *remote_enumerator = NULL; - - if (!enumerate_refs_recurse (repo, NULL, repo->local_heads_dir, repo->local_heads_dir, - ret_all_refs, - cancellable, error)) - goto out; - - remote_enumerator = g_file_enumerate_children (repo->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO, - 0, - cancellable, error); - - while (TRUE) - { - GFileInfo *info; - GFile *child; - const char *name; - - if (!gs_file_enumerator_iterate (remote_enumerator, &info, &child, - cancellable, error)) - goto out; - if (!info) - break; - - name = g_file_info_get_name (info); - if (!enumerate_refs_recurse (repo, name, child, child, - ret_all_refs, - cancellable, error)) - goto out; - } - } - - ret = TRUE; - ot_transfer_out_value (out_all_refs, &ret_all_refs); - out: - return ret; -} - -static gboolean -write_ref_summary (OstreeRepo *self, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - GHashTableIter hash_iter; - gpointer key, value; - gsize bytes_written; - gs_unref_hashtable GHashTable *all_refs = NULL; - gs_unref_object GFile *summary_path = NULL; - gs_unref_object GOutputStream *out = NULL; - gs_free char *buf = NULL; - - if (!ostree_repo_list_refs (self, NULL, &all_refs, cancellable, error)) - goto out; - - summary_path = g_file_resolve_relative_path (ostree_repo_get_path (self), - "refs/summary"); - - out = (GOutputStream*) g_file_replace (summary_path, NULL, FALSE, 0, cancellable, error); - if (!out) - goto out; - - g_hash_table_iter_init (&hash_iter, all_refs); - while (g_hash_table_iter_next (&hash_iter, &key, &value)) - { - const char *name = key; - const char *sha256 = value; - - g_free (buf); - buf = g_strdup_printf ("%s %s\n", sha256, name); - if (!g_output_stream_write_all (out, buf, strlen (buf), &bytes_written, cancellable, error)) - goto out; - } - - if (!g_output_stream_close (out, cancellable, error)) - goto out; - - ret = TRUE; - out: - return ret; -} - -gboolean -ostree_repo_write_ref (OstreeRepo *self, - const char *remote, - const char *name, - const char *rev, - GError **error) -{ - gboolean ret = FALSE; - gs_unref_object GFile *dir = NULL; - - if (remote == NULL) - dir = g_object_ref (self->local_heads_dir); - else - { - dir = g_file_get_child (self->remote_heads_dir, remote); - - if (rev != NULL) - { - if (!gs_file_ensure_directory (dir, FALSE, NULL, error)) - goto out; - } - } - - if (rev == NULL) - { - gs_unref_object GFile *child = g_file_resolve_relative_path (dir, name); - - if (g_file_query_exists (child, NULL)) - { - if (!gs_file_unlink (child, NULL, error)) - goto out; - } - } - else - { - if (!write_checksum_file (dir, name, rev, error)) - goto out; - - if (rev != NULL) - { - if (self->mode == OSTREE_REPO_MODE_ARCHIVE - || self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2) - { - if (!write_ref_summary (self, NULL, error)) - goto out; - } - } - } - - ret = TRUE; - out: - return ret; -} - -gboolean -ostree_repo_write_refspec (OstreeRepo *self, - const char *refspec, - const char *rev, - GError **error) -{ - gboolean ret = FALSE; - gs_free char *remote = NULL; - gs_free char *ref = NULL; - - if (!ostree_parse_refspec (refspec, &remote, &ref, error)) - goto out; - - if (!ostree_repo_write_ref (self, remote, ref, rev, error)) - goto out; - - ret = TRUE; - out: - return ret; -} - gboolean ostree_repo_stage_commit (OstreeRepo *self, const char *branch,