diff options
author | Colin Walters <walters@verbum.org> | 2014-07-31 18:50:19 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2014-08-04 16:14:35 -0400 |
commit | 53b7bc3b469c783b0db899b3797672e377b8d9e6 (patch) | |
tree | 48ed5ed3ae86f4bfd56cba992a6c814e66e4b247 | |
parent | 9bd229dff58ddb96f08e9307a1a668efc3548db5 (diff) | |
download | ostree-53b7bc3b469c783b0db899b3797672e377b8d9e6.tar.gz |
WIP: metalink code
-rw-r--r-- | Makefile-libostree.am | 2 | ||||
-rw-r--r-- | src/libostree/ostree-metalink.c | 314 | ||||
-rw-r--r-- | src/libostree/ostree-metalink.h | 62 | ||||
-rw-r--r-- | src/libostree/ostree-repo-pull.c | 28 |
4 files changed, 398 insertions, 8 deletions
diff --git a/Makefile-libostree.am b/Makefile-libostree.am index 1b756001..e7b141ae 100644 --- a/Makefile-libostree.am +++ b/Makefile-libostree.am @@ -112,6 +112,8 @@ if USE_LIBSOUP libostree_1_la_SOURCES += \ src/libostree/ostree-fetcher.h \ src/libostree/ostree-fetcher.c \ + src/libostree/ostree-metalink.h \ + src/libostree/ostree-metalink.c \ src/libostree/ostree-repo-pull.c \ $(NULL) libostree_1_la_CFLAGS += $(OT_INTERNAL_SOUP_CFLAGS) diff --git a/src/libostree/ostree-metalink.c b/src/libostree/ostree-metalink.c new file mode 100644 index 00000000..f217461e --- /dev/null +++ b/src/libostree/ostree-metalink.c @@ -0,0 +1,314 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters <walters@verbum.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-metalink.h" + +#include "otutil.h" +#include "libgsystem.h" + +typedef enum { + OSTREE_METALINK_STATE_INITIAL, + OSTREE_METALINK_STATE_METALINK, + OSTREE_METALINK_STATE_FILES, + OSTREE_METALINK_STATE_FILE, + OSTREE_METALINK_STATE_SIZE, + OSTREE_METALINK_STATE_VERIFICATION, + OSTREE_METALINK_STATE_HASH, + OSTREE_METALINK_STATE_RESOURCES, + OSTREE_METALINK_STATE_URL, + + OSTREE_METALINK_STATE_PASSTHROUGH, /* Ignoring unknown elements */ + OSTREE_METALINK_STATE_ERROR +} OstreeMetalinkState; + +struct OstreeMetalink +{ + GObject parent_instance; + + OstreeMetalink *fetcher; + + guint passthrough_depth; + OstreeMetalinkState passthrough_previous; + + char *file_name; + guint64 size; + guint verification_known :1; + GChecksumType verification_type; + char *verification_value; + + GPtrArray *urls; + + OstreeMetalinkState state; +}; + +G_DEFINE_TYPE (OstreeMetalink, _ostree_metalink, G_TYPE_OBJECT) + +static void +state_transition (OstreeMetalink *self, + OstreeMetalinkState new_state) +{ + g_assert (self->state != new_state); + self->state = new_state; +} + +static void +unknown_element (OstreeMetalink *self, + const char *element_name, + GError **error) +{ + state_transition (self, OSTREE_METALINK_STATE_PASSTHROUGH); + g_assert (self->passthrough_depth == 0); +} + +static void +metalink_parser_start (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + OstreeMetalink *self = user_data; + + switch (self->state) + { + case OSTREE_METALINK_STATE_INITIAL: + if (strcmp (element_name, "metalink") == 0) + state_transition (self, OSTREE_METALINK_STATE_METALINK); + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_METALINK: + if (strcmp (element_name, "files") == 0) + state_transition (self, OSTREE_METALINK_STATE_FILES); + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_FILES: + if (strcmp (element_name, "file") == 0) + { + const char *file_name; + + state_transition (self, OSTREE_METALINK_STATE_FILE); + + g_clear_pointer (&self->file_name, g_free); + if (!g_markup_collect_attributes (element_name, + attribute_names, + attribute_values, + error, + G_MARKUP_COLLECT_STRING, + "name", + &file_name, + G_MARKUP_COLLECT_INVALID)) + goto out; + + self->file_name = g_strdup (file_name); + } + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_FILE: + if (strcmp (element_name, "size") == 0) + state_transition (self, OSTREE_METALINK_STATE_SIZE); + else if (strcmp (element_name, "verification") == 0) + state_transition (self, OSTREE_METALINK_STATE_VERIFICATION); + else if (strcmp (element_name, "resources") == 0) + state_transition (self, OSTREE_METALINK_STATE_RESOURCES); + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_SIZE: + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_VERIFICATION: + if (strcmp (element_name, "hash") == 0) + { + gs_free char *verification_type_str = NULL; + + state_transition (self, OSTREE_METALINK_STATE_HASH); + if (!g_markup_collect_attributes (element_name, + attribute_names, + attribute_values, + error, + G_MARKUP_COLLECT_STRING, + "name", + &verification_type_str, + G_MARKUP_COLLECT_INVALID)) + goto out; + + /* Only accept sha256/sha512 */ + self->verification_known = TRUE; + if (strcmp (verification_type_str, "sha256") == 0) + self->verification_type = G_CHECKSUM_SHA256; + else if (strcmp (verification_type_str, "sha512") == 0) + self->verification_type = G_CHECKSUM_SHA512; + else + self->verification_known = FALSE; + } + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_HASH: + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_RESOURCES: + if (strcmp (element_name, "url") == 0) + { + const char *protocol; + + if (!g_markup_collect_attributes (element_name, + attribute_names, + attribute_values, + error, + G_MARKUP_COLLECT_STRING, + "protocol", + &protocol, + G_MARKUP_COLLECT_INVALID)) + goto out; + + /* Ignore non-HTTP resources */ + if (!(strcmp (protocol, "http") == 0 || strcmp (protocol, "https") == 0)) + state_transition (self, OSTREE_METALINK_STATE_PASSTHROUGH); + else + state_transition (self, OSTREE_METALINK_STATE_URL); + } + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_URL: + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_PASSTHROUGH: + self->passthrough_depth++; + break; + default: + g_assert_not_reached (); + } + + out: + return; +} + +static void +metalink_parser_end (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + OstreeMetalink *self = user_data; +} + +static void +metalink_parser_text (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + OstreeMetalink *self = user_data; + + switch (self->state) + { + case OSTREE_METALINK_STATE_INITIAL: + break; + case OSTREE_METALINK_STATE_METALINK: + break; + case OSTREE_METALINK_STATE_FILES: + break; + case OSTREE_METALINK_STATE_FILE: + break; + case OSTREE_METALINK_STATE_SIZE: + { + gs_free char *duped = g_strndup (text, text_len); + self->size = g_ascii_strtoull (duped, NULL, 10); + } + break; + case OSTREE_METALINK_STATE_VERIFICATION: + break; + case OSTREE_METALINK_STATE_HASH: + { + g_clear_pointer (&self->verification_value, g_free); + self->verification_value = g_strndup (text, text_len); + } + break; + case OSTREE_METALINK_STATE_RESOURCES: + break; + case OSTREE_METALINK_STATE_URL: + break; + case OSTREE_METALINK_STATE_PASSTHROUGH: + break; + default: + g_assert_not_reached (); + } + out: + return; +} + +static void +_ostree_metalink_finalize (GObject *object) +{ + OstreeMetalink *self; + + self = OSTREE_METALINK (object); + + G_OBJECT_CLASS (_ostree_metalink_parent_class)->finalize (object); +} + +static void +_ostree_metalink_class_init (OstreeMetalinkClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = _ostree_metalink_finalize; +} + +static void +_ostree_metalink_init (OstreeMetalink *self) +{ + self->urls = g_ptr_array_new_with_free_func (g_free); +} + +OstreeMetalink * +_ostree_metalink_new (OstreeFetcher *fetcher, + const char *requested_file, + guint64 max_size, + SoupURI *uri) +{ + OstreeMetalink *self = (OstreeMetalink*)g_object_new (OSTREE_TYPE_METALINK, NULL); + + return self; +} + +void +_ostree_metalink_request_async (OstreeMetalink *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ +} + +GFile * +_ostree_metalink_request_finish (OstreeMetalink *self, + GAsyncResult *result, + GError **error) +{ +} diff --git a/src/libostree/ostree-metalink.h b/src/libostree/ostree-metalink.h new file mode 100644 index 00000000..bb81292c --- /dev/null +++ b/src/libostree/ostree-metalink.h @@ -0,0 +1,62 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters <walters@verbum.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#ifndef __GI_SCANNER__ + +#include "ostree-fetcher.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_METALINK (_ostree_metalink_get_type ()) +#define OSTREE_METALINK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_METALINK, OstreeMetalink)) +#define OSTREE_METALINK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_METALINK, OstreeMetalinkClass)) +#define OSTREE_IS_METALINK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_METALINK)) +#define OSTREE_IS_METALINK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_METALINK)) +#define OSTREE_METALINK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_METALINK, OstreeMetalinkClass)) + +typedef struct OstreeMetalinkClass OstreeMetalinkClass; +typedef struct OstreeMetalink OstreeMetalink; + +struct OstreeMetalinkClass +{ + GObjectClass parent_class; +}; + +GType _ostree_metalink_get_type (void) G_GNUC_CONST; + +OstreeMetalink *_ostree_metalink_new (OstreeFetcher *fetcher, + const char *requested_file, + guint64 max_size, + SoupURI *uri); + +void _ostree_metalink_request_async (OstreeMetalink *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GFile *_ostree_metalink_request_finish (OstreeMetalink *self, + GAsyncResult *result, + GError **error); + +G_END_DECLS + +#endif diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index 2cdc6c15..9be8f324 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -1030,6 +1030,7 @@ ostree_repo_pull (OstreeRepo *self, gs_free char *remote_key = NULL; gs_free char *path = NULL; gs_free char *baseurl = NULL; + gs_free char *metalink_url = NULL; gs_unref_hashtable GHashTable *requested_refs_to_fetch = NULL; gs_unref_hashtable GHashTable *commits_to_fetch = NULL; gs_free char *remote_mode_str = NULL; @@ -1070,11 +1071,29 @@ ostree_repo_pull (OstreeRepo *self, remote_key); goto out; } - if (!repo_get_string_key_inherit (self, remote_key, "url", &baseurl, error)) + + if (!ot_keyfile_get_value_with_default (self, remote_key, "metalink", &metalink_url, error)) goto out; + if (!metalink_url) + { + if (!repo_get_string_key_inherit (self, remote_key, "url", &baseurl, error)) + goto out; + } + else + { + FIXME - need to retrieve the metalink value, extract checksum for ref from it + } + pull_data->base_uri = soup_uri_new (baseurl); + if (!pull_data->base_uri) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to parse url '%s'", baseurl); + goto out; + } + #ifdef HAVE_GPGME if (!ot_keyfile_get_boolean_with_default (config, remote_key, "gpg-verify", TRUE, &pull_data->gpg_verify, error)) @@ -1148,13 +1167,6 @@ ostree_repo_pull (OstreeRepo *self, } } - if (!pull_data->base_uri) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Failed to parse url '%s'", baseurl); - goto out; - } - if (!load_remote_repo_config (pull_data, &remote_config, cancellable, error)) goto out; |