[ostree/wip/metalinks: 1/2] WIP: metalink code



commit 53b7bc3b469c783b0db899b3797672e377b8d9e6
Author: Colin Walters <walters verbum org>
Date:   Thu Jul 31 18:50:19 2014 -0400

    WIP: metalink code

 Makefile-libostree.am            |    2 +
 src/libostree/ostree-metalink.c  |  314 ++++++++++++++++++++++++++++++++++++++
 src/libostree/ostree-metalink.h  |   62 ++++++++
 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 1b75600..e7b141a 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 0000000..f217461
--- /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 0000000..bb81292
--- /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 2cdc6c1..9be8f32 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;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]