]> git.ipfire.org Git - pakfire.git/commitdiff
downloader: Split mirrors and mirrorlists into their own files
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 16 Oct 2023 15:33:54 +0000 (15:33 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 16 Oct 2023 15:33:54 +0000 (15:33 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/libpakfire/dist.c
src/libpakfire/downloader.c
src/libpakfire/include/pakfire/downloader.h
src/libpakfire/include/pakfire/mirror.h [new file with mode: 0644]
src/libpakfire/include/pakfire/mirrorlist.h [new file with mode: 0644]
src/libpakfire/include/pakfire/util.h
src/libpakfire/mirror.c [new file with mode: 0644]
src/libpakfire/mirrorlist.c [new file with mode: 0644]
src/libpakfire/repo.c
src/libpakfire/util.c

index c75aa91e5abe537146cd13f6e45eca6cf5172ff6..30c12240d3f726c377af7ed25e4d992710c935f8 100644 (file)
@@ -230,6 +230,8 @@ libpakfire_la_SOURCES = \
        src/libpakfire/key.c \
        src/libpakfire/linter.c \
        src/libpakfire/logging.c \
+       src/libpakfire/mirror.c \
+       src/libpakfire/mirrorlist.c \
        src/libpakfire/mount.c \
        src/libpakfire/package.c \
        src/libpakfire/packager.c \
@@ -271,6 +273,8 @@ pkginclude_HEADERS += \
        src/libpakfire/include/pakfire/key.h \
        src/libpakfire/include/pakfire/linter.h \
        src/libpakfire/include/pakfire/logging.h \
+       src/libpakfire/include/pakfire/mirror.h \
+       src/libpakfire/include/pakfire/mirrorlist.h \
        src/libpakfire/include/pakfire/mount.h \
        src/libpakfire/include/pakfire/package.h \
        src/libpakfire/include/pakfire/packager.h \
index e7ebba390b17dd9b3aff28390f25061c8b926624..bc649571316b93270ca3f4c5fb0645d38219c683 100644 (file)
@@ -31,6 +31,8 @@
 #include <pakfire/i18n.h>
 #include <pakfire/linter.h>
 #include <pakfire/logging.h>
+#include <pakfire/mirror.h>
+#include <pakfire/mirrorlist.h>
 #include <pakfire/package.h>
 #include <pakfire/packager.h>
 #include <pakfire/pakfire.h>
@@ -222,7 +224,9 @@ ERROR:
 
 static int pakfire_dist_get_mirrorlist(struct pakfire* pakfire,
                struct pakfire_parser* makefile, struct pakfire_mirrorlist** list) {
+       struct pakfire_ctx* ctx = pakfire_ctx(pakfire);
        struct pakfire_mirrorlist* m = NULL;
+       struct pakfire_mirror* mirror = NULL;
        char* p = NULL;
        int r;
 
@@ -234,20 +238,27 @@ static int pakfire_dist_get_mirrorlist(struct pakfire* pakfire,
                return 0;
 
        // Create mirrorlist
-       r = pakfire_mirrorlist_create(&m, pakfire);
+       r = pakfire_mirrorlist_create(&m, ctx);
        if (r) {
                ERROR(pakfire, "Could not create the mirrorlist\n");
                goto ERROR;
        }
 
        // Add all mirrors
-       const char* mirror = strtok_r(source_dl, " ", &p);
-       while (mirror) {
+       const char* url = strtok_r(source_dl, " ", &p);
+       while (url) {
+               // Create a new mirror
+               r = pakfire_mirror_create(&mirror, ctx, url);
+               if (r)
+                       goto ERROR;
+
+               // Add the mirror to the mirrorlist
                r = pakfire_mirrorlist_add_mirror(m, mirror);
+               pakfire_mirror_unref(mirror);
                if (r)
                        goto ERROR;
 
-               mirror = strtok_r(NULL, " ", &p);
+               url = strtok_r(NULL, " ", &p);
        }
 
        // Success
@@ -256,6 +267,8 @@ static int pakfire_dist_get_mirrorlist(struct pakfire* pakfire,
 ERROR:
        if (m)
                pakfire_mirrorlist_unref(m);
+       if (ctx)
+               pakfire_ctx_unref(ctx);
        if (source_dl)
                free(source_dl);
 
index a8a13a9b57570052c0fdac560b1bd97425edfc5f..d5862b41c07e1c0862649d546c12a39e2ee1f724 100644 (file)
 #include <pakfire/string.h>
 #include <pakfire/util.h>
 
-// Retry a mirror up to N times before marking it as broken
-#define MIRROR_RETRIES                 3
-
 // The number of concurrent downloads
 #define MAX_PARALLEL                   4
 
-struct pakfire_mirror {
-       STAILQ_ENTRY(pakfire_mirror) nodes;
-
-       char url[PATH_MAX];
-
-       unsigned int retries_left;
-       int broken;
-};
-
 struct pakfire_transfer {
        struct pakfire* pakfire;
        int nrefs;
@@ -101,7 +89,6 @@ struct pakfire_downloader {
        struct pakfire* pakfire;
        int nrefs;
 
-//     struct pakfire_progress* progress;
        unsigned int parallel;
 
        // cURL multi handle
@@ -159,6 +146,8 @@ static void pakfire_downloader_transfer_free(struct pakfire_transfer* transfer)
        if (transfer->evp)
                EVP_MD_CTX_free(transfer->evp);
 
+       if (transfer->mirror)
+               pakfire_mirror_unref(transfer->mirror);
        if (transfer->mirrors)
                pakfire_mirrorlist_unref(transfer->mirrors);
        if (transfer->progress)
@@ -543,16 +532,16 @@ static int pakfire_transfer_select_mirror(struct pakfire_downloader* downloader,
                struct pakfire_transfer* transfer) {
        // Choose the next mirror
        if (transfer->mirror)
-               transfer->mirror = STAILQ_NEXT(transfer->mirror, nodes);
+               transfer->mirror = pakfire_mirrorlist_get_next(transfer->mirrors, transfer->mirror);
 
        // If no mirror has been selected yet, choose the first one
        else
-               transfer->mirror = pakfire_mirrorlist_first(transfer->mirrors);
+               transfer->mirror = pakfire_mirrorlist_get_first(transfer->mirrors);
 
        // Skip this mirror if it is broken
-       while (transfer->mirror && transfer->mirror->broken) {
+       while (transfer->mirror && pakfire_mirror_is_broken(transfer->mirror)) {
                // Move on to the next mirror
-               transfer->mirror = STAILQ_NEXT(transfer->mirror, nodes);
+               transfer->mirror = pakfire_mirrorlist_get_next(transfer->mirrors, transfer->mirror);
        }
 
        // No mirror found
@@ -563,7 +552,7 @@ static int pakfire_transfer_select_mirror(struct pakfire_downloader* downloader,
                return ENOENT;
        }
 
-       DEBUG(downloader->pakfire, "Selected mirror %s\n", transfer->mirror->url);
+       DEBUG(downloader->pakfire, "Selected mirror %s\n", pakfire_mirror_get_url(transfer->mirror));
 
        return 0;
 }
@@ -650,12 +639,7 @@ static int pakfire_transfer_fail(struct pakfire_downloader* downloader,
 
        // Did we use a mirror?
        if (transfer->mirror) {
-               // Decrease retries and potentially mark mirror as broken
-               if (!transfer->mirror->retries_left--) {
-                       DEBUG(downloader->pakfire, "Mark mirror %s as broken\n",
-                               transfer->mirror->url);
-                       transfer->mirror->broken = 1;
-               }
+               pakfire_mirror_transfer_failed(transfer->mirror);
 
                // Try again with another mirror
                return EAGAIN;
@@ -918,7 +902,7 @@ static int pakfire_downloader_transfer_prepare(struct pakfire_downloader* downlo
                if (r)
                        return r;
 
-               r = pakfire_url_join(url, transfer->mirror->url, transfer->url);
+               r = pakfire_url_join(url, pakfire_mirror_get_url(transfer->mirror), transfer->url);
                if (r)
                        return r;
 
@@ -1215,185 +1199,3 @@ ERROR:
 
        return r;
 }
-
-struct pakfire_mirrorlist {
-       struct pakfire* pakfire;
-       int nrefs;
-
-       STAILQ_HEAD(mirrors, pakfire_mirror) mirrors;
-};
-
-static void pakfire_mirrorlist_clear(struct pakfire_mirrorlist* ml) {
-       while (!STAILQ_EMPTY(&ml->mirrors)) {
-               struct pakfire_mirror* mirror = STAILQ_FIRST(&ml->mirrors);
-               STAILQ_REMOVE_HEAD(&ml->mirrors, nodes);
-               free(mirror);
-       }
-}
-
-static void pakfire_mirrorlist_free(struct pakfire_mirrorlist* ml) {
-       pakfire_mirrorlist_clear(ml);
-
-       pakfire_unref(ml->pakfire);
-       free(ml);
-}
-
-int pakfire_mirrorlist_create(struct pakfire_mirrorlist** mirrorlist, struct pakfire* pakfire) {
-       struct pakfire_mirrorlist* ml = calloc(1, sizeof(*ml));
-       if (!ml)
-               return ENOMEM;
-
-       ml->pakfire = pakfire_ref(pakfire);
-       ml->nrefs = 1;
-
-       // Init mirrors
-       STAILQ_INIT(&ml->mirrors);
-
-       *mirrorlist = ml;
-
-       return 0;
-}
-
-struct pakfire_mirrorlist* pakfire_mirrorlist_ref(struct pakfire_mirrorlist* ml) {
-       ++ml->nrefs;
-
-       return ml;
-}
-
-struct pakfire_mirrorlist* pakfire_mirrorlist_unref(struct pakfire_mirrorlist* ml) {
-       if (--ml->nrefs > 0)
-               return ml;
-
-       pakfire_mirrorlist_free(ml);
-
-       return NULL;
-}
-
-static int pakfire_mirrorlist_check_mirrorlist(struct pakfire_mirrorlist* ml,
-               struct json_object* root) {
-       struct json_object* typeobj = NULL;
-       int r = 1;
-
-       r = json_object_object_get_ex(root, "type", &typeobj);
-       if (!r) {
-               ERROR(ml->pakfire, "mirrorlist does not have a 'type' attribute\n");
-               goto ERROR;
-       }
-
-       const char* type = json_object_get_string(typeobj);
-       if (!type) {
-               ERROR(ml->pakfire, "mirrorlist has an empty or unknown 'type' attribute\n");
-               goto ERROR;
-       }
-
-       if (strcmp(type, "mirrorlist") != 0) {
-               ERROR(ml->pakfire, "Unexpected type: %s\n", type);
-               goto ERROR;
-       }
-
-       // Success
-       r = 0;
-
-ERROR:
-       if (typeobj)
-               json_object_put(typeobj);
-
-       return r;
-}
-
-int pakfire_mirrorlist_read(struct pakfire_mirrorlist* ml, const char* path) {
-       if (!path || !*path) {
-               errno = EINVAL;
-               return 1;
-       }
-
-       DEBUG(ml->pakfire, "Reading mirrorlist from %s\n", path);
-
-       struct json_object* json = pakfire_json_parse_from_file(ml->pakfire, path);
-       if (!json) {
-               // Ignore if path does not exist
-               if (errno == ENOENT)
-                       return 0;
-
-               ERROR(ml->pakfire, "Could not parse mirrorlist from %s: %m\n", path);
-               return 1;
-       }
-
-       struct json_object* mirrors = NULL;
-
-       // Check if we found a valid mirrorlist
-       int r = pakfire_mirrorlist_check_mirrorlist(ml, json);
-       if (r)
-               goto ERROR;
-
-       // Clear all existing mirrors
-       pakfire_mirrorlist_clear(ml);
-
-       // Add the new mirrors
-       r = json_object_object_get_ex(json, "mirrors", &mirrors);
-       if (!r) {
-               DEBUG(ml->pakfire, "Mirrorlist has no mirrors\n");
-               r = 0;
-               goto ERROR;
-       }
-
-       size_t num_mirrors = json_object_array_length(mirrors);
-
-       for (unsigned int i = 0; i < num_mirrors; i++) {
-               struct json_object* mirror = json_object_array_get_idx(mirrors, i);
-               if (!mirror)
-                       continue;
-
-               // Find URL
-               struct json_object* urlobj;
-               r = json_object_object_get_ex(mirror, "url", &urlobj);
-               if (!r)
-                       goto ERROR;
-
-               const char* url = json_object_get_string(urlobj);
-
-               // Add the mirror to the downloader
-               r = pakfire_mirrorlist_add_mirror(ml, url);
-               if (r) {
-                       ERROR(ml->pakfire, "Could not add mirror %s: %m\n", url);
-                       goto ERROR;
-               }
-       }
-
-       // Success
-       r = 0;
-
-ERROR:
-       if (json)
-               json_object_put(json);
-
-       return r;
-}
-
-int pakfire_mirrorlist_add_mirror(struct pakfire_mirrorlist* ml, const char* url) {
-       // Allocate a new mirror object
-       struct pakfire_mirror* mirror = calloc(1, sizeof(*mirror));
-       if (!mirror)
-               return ENOMEM;
-
-       // Copy URL
-       pakfire_string_set(mirror->url, url);
-
-       // Set retries
-       mirror->retries_left = MIRROR_RETRIES;
-
-       // Append it to the list
-       STAILQ_INSERT_TAIL(&ml->mirrors, mirror, nodes);
-
-       DEBUG(ml->pakfire, "Added mirror %s\n", mirror->url);
-
-       return 0;
-}
-
-int pakfire_mirrorlist_empty(struct pakfire_mirrorlist* ml) {
-       return STAILQ_EMPTY(&ml->mirrors);
-}
-
-struct pakfire_mirror* pakfire_mirrorlist_first(struct pakfire_mirrorlist* ml) {
-       return STAILQ_FIRST(&ml->mirrors);
-}
index d2a1bd1caa31b347079a6368754fe5bda74c78e2..0f36f95a5c62bdd92df31bdb371811857c3ff0eb 100644 (file)
@@ -24,9 +24,9 @@
 #ifdef PAKFIRE_PRIVATE
 
 struct pakfire_downloader;
-struct pakfire_mirrorlist;
 
 #include <pakfire/digest.h>
+#include <pakfire/mirrorlist.h>
 #include <pakfire/pakfire.h>
 
 enum pakfire_transfer_flags {
@@ -63,19 +63,6 @@ int pakfire_downloader_transfer_set_target(struct pakfire_transfer* transfer, co
 int pakfire_downloader_transfer_run(struct pakfire_transfer* transfer, int flags);
 int pakfire_downloader_run(struct pakfire_downloader* downloader, const char* title);
 
-// Mirror lists
-
-int pakfire_mirrorlist_create(struct pakfire_mirrorlist** ml, struct pakfire* pakfire);
-
-struct pakfire_mirrorlist* pakfire_mirrorlist_ref(struct pakfire_mirrorlist* ml);
-struct pakfire_mirrorlist* pakfire_mirrorlist_unref(struct pakfire_mirrorlist* ml);
-
-int pakfire_mirrorlist_read(struct pakfire_mirrorlist* ml, const char* path);
-int pakfire_mirrorlist_add_mirror(struct pakfire_mirrorlist* ml, const char* url);
-
-int pakfire_mirrorlist_empty(struct pakfire_mirrorlist* ml);
-struct pakfire_mirror* pakfire_mirrorlist_first(struct pakfire_mirrorlist* ml);
-
-#endif
+#endif /* PAKFIRE_PRIVATE */
 
 #endif /* PAKFIRE_DOWNLOADER_H */
diff --git a/src/libpakfire/include/pakfire/mirror.h b/src/libpakfire/include/pakfire/mirror.h
new file mode 100644 (file)
index 0000000..3796671
--- /dev/null
@@ -0,0 +1,43 @@
+/*#############################################################################
+#                                                                             #
+# Pakfire - The IPFire package management system                              #
+# Copyright (C) 2023 Pakfire development team                                 #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program 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 General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#ifndef PAKFIRE_MIRROR_H
+#define PAKFIRE_MIRROR_H
+
+struct pakfire_mirror;
+
+#include <pakfire/ctx.h>
+
+int pakfire_mirror_create(struct pakfire_mirror** mirror,
+       struct pakfire_ctx* ctx, const char* url);
+
+struct pakfire_mirror* pakfire_mirror_ref(struct pakfire_mirror* mirror);
+struct pakfire_mirror* pakfire_mirror_unref(struct pakfire_mirror* mirror);
+
+const char* pakfire_mirror_get_url(struct pakfire_mirror* mirror);
+
+// Broken?
+
+int pakfire_mirror_is_broken(struct pakfire_mirror* mirror);
+void pakfire_mirror_mark_as_broken(struct pakfire_mirror* mirror);
+
+void pakfire_mirror_transfer_failed(struct pakfire_mirror* mirror);
+
+#endif /* PAKFIRE_MIRROR_H */
diff --git a/src/libpakfire/include/pakfire/mirrorlist.h b/src/libpakfire/include/pakfire/mirrorlist.h
new file mode 100644 (file)
index 0000000..9330b23
--- /dev/null
@@ -0,0 +1,49 @@
+/*#############################################################################
+#                                                                             #
+# Pakfire - The IPFire package management system                              #
+# Copyright (C) 2023 Pakfire development team                                 #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program 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 General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#ifndef PAKFIRE_MIRRORLIST_H
+#define PAKFIRE_MIRRORLIST_H
+
+#ifdef PAKFIRE_PRIVATE
+
+struct pakfire_mirrorlist;
+
+#include <pakfire/ctx.h>
+#include <pakfire/mirror.h>
+
+int pakfire_mirrorlist_create(struct pakfire_mirrorlist** list, struct pakfire_ctx* ctx);
+
+struct pakfire_mirrorlist* pakfire_mirrorlist_ref(struct pakfire_mirrorlist* list);
+struct pakfire_mirrorlist* pakfire_mirrorlist_unref(struct pakfire_mirrorlist* list);
+
+int pakfire_mirrorlist_read(struct pakfire_mirrorlist* list, const char* path);
+
+int pakfire_mirrorlist_add_mirror(
+       struct pakfire_mirrorlist* list, struct pakfire_mirror* mirror);
+
+int pakfire_mirrorlist_empty(struct pakfire_mirrorlist* ml);
+
+struct pakfire_mirror* pakfire_mirrorlist_get_first(struct pakfire_mirrorlist* list);
+struct pakfire_mirror* pakfire_mirrorlist_get_next(
+       struct pakfire_mirrorlist* list, struct pakfire_mirror* mirror);
+
+#endif /* PAKFIRE_PRIVATE */
+
+#endif /* PAKFIRE_MIRRORLIST_H */
index 7af64b5f65e0a9d9fd8e77735f0f32e6196da9e5..2bad16130aa3ce529d5c823b0f7fba6bcf406325 100644 (file)
@@ -31,6 +31,7 @@
 #define PCRE2_CODE_UNIT_WIDTH 8
 #include <pcre2.h>
 
+#include <pakfire/ctx.h>
 #include <pakfire/digest.h>
 #include <pakfire/pakfire.h>
 
@@ -102,7 +103,7 @@ int pakfire_archive_copy_data_to_buffer(struct pakfire* pakfire, struct archive*
 
 // JSON Stuff
 
-struct json_object* pakfire_json_parse_from_file(struct pakfire* pakfire, const char* path);
+struct json_object* pakfire_json_parse_from_file(struct pakfire_ctx* ctx, const char* path);
 int pakfire_json_add_string(struct pakfire* pakfire,
        struct json_object* json, const char* name, const char* value);
 int pakfire_json_add_integer(struct pakfire* pakfire,
diff --git a/src/libpakfire/mirror.c b/src/libpakfire/mirror.c
new file mode 100644 (file)
index 0000000..6cf4069
--- /dev/null
@@ -0,0 +1,117 @@
+/*#############################################################################
+#                                                                             #
+# Pakfire - The IPFire package management system                              #
+# Copyright (C) 2023 Pakfire development team                                 #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program 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 General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <pakfire/mirror.h>
+#include <pakfire/pakfire.h>
+#include <pakfire/string.h>
+
+// Retry a mirror up to N times before marking it as broken
+#define MIRROR_RETRIES                 3
+
+struct pakfire_mirror {
+       struct pakfire_ctx* ctx;
+       int nrefs;
+
+       char url[PATH_MAX];
+
+       unsigned int retries_left;
+
+       // Set if the mirror is considered broken
+       int is_broken;
+};
+
+static void pakfire_mirror_free(struct pakfire_mirror* mirror) {
+       if (mirror->ctx)
+               pakfire_ctx_unref(mirror->ctx);
+
+       free(mirror);
+}
+
+int pakfire_mirror_create(struct pakfire_mirror** mirror,
+               struct pakfire_ctx* ctx, const char* url) {
+       struct pakfire_mirror* m = NULL;
+       int r;
+
+       // Allocate the mirror
+       m = calloc(1, sizeof(*m));
+       if (!m)
+               return -errno;
+
+       // Store a reference to the context
+       m->ctx = pakfire_ctx_ref(ctx);
+
+       // Initialize the reference counter
+       m->nrefs = 1;
+
+       // Store the URL
+       r = pakfire_string_set(m->url, url);
+       if (r)
+               goto ERROR;
+
+       // Set the default retries
+       m->retries_left = MIRROR_RETRIES;
+
+       // Return the pointer
+       *mirror = pakfire_mirror_ref(m);
+
+ERROR:
+       if (m)
+               pakfire_mirror_unref(m);
+
+       return r;
+}
+
+struct pakfire_mirror* pakfire_mirror_ref(struct pakfire_mirror* mirror) {
+       ++mirror->nrefs;
+
+       return mirror;
+}
+
+struct pakfire_mirror* pakfire_mirror_unref(struct pakfire_mirror* mirror) {
+       if (--mirror->nrefs > 0)
+               return mirror;
+
+       pakfire_mirror_free(mirror);
+       return NULL;
+}
+
+const char* pakfire_mirror_get_url(struct pakfire_mirror* mirror) {
+       return mirror->url;
+}
+
+// Broken
+
+int pakfire_mirror_is_broken(struct pakfire_mirror* mirror) {
+       return mirror->is_broken;
+}
+
+void pakfire_mirror_mark_as_broken(struct pakfire_mirror* mirror) {
+       CTX_DEBUG(mirror->ctx, "Mirror %s has been marked as broken\n", mirror->url);
+
+       mirror->is_broken = 1;
+}
+
+void pakfire_mirror_transfer_failed(struct pakfire_mirror* mirror) {
+       if (!mirror->retries_left--)
+               pakfire_mirror_mark_as_broken(mirror);
+}
diff --git a/src/libpakfire/mirrorlist.c b/src/libpakfire/mirrorlist.c
new file mode 100644 (file)
index 0000000..d3b468a
--- /dev/null
@@ -0,0 +1,255 @@
+/*#############################################################################
+#                                                                             #
+# Pakfire - The IPFire package management system                              #
+# Copyright (C) 2023 Pakfire development team                                 #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program 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 General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <pakfire/ctx.h>
+#include <pakfire/logging.h>
+#include <pakfire/mirror.h>
+#include <pakfire/mirrorlist.h>
+#include <pakfire/util.h>
+
+struct pakfire_mirrorlist {
+       struct pakfire_ctx* ctx;
+       int nrefs;
+
+       // Mirrors
+       struct pakfire_mirror** mirrors;
+       unsigned int num_mirrors;
+};
+
+static void pakfire_mirrorlist_clear(struct pakfire_mirrorlist* list) {
+       if (list->mirrors) {
+               for (unsigned int i = 0; i < list->num_mirrors; i++)
+                       pakfire_mirror_unref(list->mirrors[i]);
+
+               free(list->mirrors);
+
+               list->mirrors = NULL;
+               list->num_mirrors = 0;
+       }
+}
+
+static void pakfire_mirrorlist_free(struct pakfire_mirrorlist* list) {
+       pakfire_mirrorlist_clear(list);
+
+       if (list->ctx)
+               pakfire_ctx_unref(list->ctx);
+       free(list);
+}
+
+int pakfire_mirrorlist_create(struct pakfire_mirrorlist** list, struct pakfire_ctx* ctx) {
+       struct pakfire_mirrorlist* l = NULL;
+
+       // Allocate a new list
+       l = calloc(1, sizeof(*l));
+       if (!l)
+               return -errno;
+
+       // Store a reference to the context
+       l->ctx = pakfire_ctx_ref(ctx);
+
+       // Initialize the reference counter
+       l->nrefs = 1;
+
+       // Return the pointer
+       *list = l;
+
+       return 0;
+}
+
+struct pakfire_mirrorlist* pakfire_mirrorlist_ref(struct pakfire_mirrorlist* list) {
+       ++list->nrefs;
+
+       return list;
+}
+
+struct pakfire_mirrorlist* pakfire_mirrorlist_unref(struct pakfire_mirrorlist* list) {
+       if (--list->nrefs > 0)
+               return list;
+
+       pakfire_mirrorlist_free(list);
+       return NULL;
+}
+
+static int pakfire_mirrorlist_check_mirrorlist(struct pakfire_mirrorlist* list,
+               struct json_object* root) {
+       struct json_object* typeobj = NULL;
+       int r = 1;
+
+       r = json_object_object_get_ex(root, "type", &typeobj);
+       if (!r) {
+               CTX_ERROR(list->ctx, "mirrorlist does not have a 'type' attribute\n");
+               goto ERROR;
+       }
+
+       const char* type = json_object_get_string(typeobj);
+       if (!type) {
+               CTX_ERROR(list->ctx, "mirrorlist has an empty or unknown 'type' attribute\n");
+               goto ERROR;
+       }
+
+       if (strcmp(type, "mirrorlist") != 0) {
+               CTX_ERROR(list->ctx, "Unexpected type: %s\n", type);
+               goto ERROR;
+       }
+
+       // Success
+       r = 0;
+
+ERROR:
+       if (typeobj)
+               json_object_put(typeobj);
+
+       return r;
+}
+
+static int pakfire_mirrorlist_add_mirror_from_url(
+               struct pakfire_mirrorlist* list, const char* url) {
+       struct pakfire_mirror* mirror = NULL;
+       int r;
+
+       // Create a new mirror object
+       r = pakfire_mirror_create(&mirror, list->ctx, url);
+       if (r)
+               goto ERROR;
+
+       // Add the mirror to the list
+       r = pakfire_mirrorlist_add_mirror(list, mirror);
+       if (r)
+               goto ERROR;
+
+ERROR:
+       if (mirror)
+               pakfire_mirror_unref(mirror);
+
+       return r;
+}
+
+int pakfire_mirrorlist_read(struct pakfire_mirrorlist* list, const char* path) {
+       if (!path || !*path) {
+               errno = EINVAL;
+               return 1;
+       }
+
+       CTX_DEBUG(list->ctx, "Reading mirrorlist from %s\n", path);
+
+       struct json_object* json = pakfire_json_parse_from_file(list->ctx, path);
+       if (!json) {
+               // Ignore if path does not exist
+               if (errno == ENOENT)
+                       return 0;
+
+               CTX_ERROR(list->ctx, "Could not parse mirrorlist from %s: %m\n", path);
+               return 1;
+       }
+
+       struct json_object* mirrors = NULL;
+
+       // Check if we found a valid mirrorlist
+       int r = pakfire_mirrorlist_check_mirrorlist(list, json);
+       if (r)
+               goto ERROR;
+
+       // Clear all existing mirrors
+       pakfire_mirrorlist_clear(list);
+
+       // Add the new mirrors
+       r = json_object_object_get_ex(json, "mirrors", &mirrors);
+       if (!r) {
+               CTX_DEBUG(list->ctx, "Mirrorlist has no mirrors\n");
+               r = 0;
+               goto ERROR;
+       }
+
+       size_t num_mirrors = json_object_array_length(mirrors);
+
+       for (unsigned int i = 0; i < num_mirrors; i++) {
+               struct json_object* mirror = json_object_array_get_idx(mirrors, i);
+               if (!mirror)
+                       continue;
+
+               // Find URL
+               struct json_object* urlobj;
+               r = json_object_object_get_ex(mirror, "url", &urlobj);
+               if (!r)
+                       goto ERROR;
+
+               const char* url = json_object_get_string(urlobj);
+
+               // Add the mirror to the downloader
+               r = pakfire_mirrorlist_add_mirror_from_url(list, url);
+               if (r) {
+                       CTX_ERROR(list->ctx, "Could not add mirror %s: %m\n", url);
+                       goto ERROR;
+               }
+       }
+
+       // Success
+       r = 0;
+
+ERROR:
+       if (json)
+               json_object_put(json);
+
+       return r;
+}
+
+int pakfire_mirrorlist_add_mirror(struct pakfire_mirrorlist* list, struct pakfire_mirror* mirror) {
+       // Check input
+       if (!mirror)
+               return -EINVAL;
+
+       // Grow the array
+       list->mirrors = reallocarray(list->mirrors, list->num_mirrors + 1, sizeof(*list->mirrors));
+       if (!list->mirrors)
+               return -errno;
+
+       // Store the mirror
+       list->mirrors[list->num_mirrors++] = pakfire_mirror_ref(mirror);
+
+       return 0;
+}
+
+int pakfire_mirrorlist_empty(struct pakfire_mirrorlist* list) {
+       return list->num_mirrors == 0;
+}
+
+struct pakfire_mirror* pakfire_mirrorlist_get_first(struct pakfire_mirrorlist* list) {
+       if (!list->num_mirrors)
+               return NULL;
+
+       return pakfire_mirror_ref(list->mirrors[0]);
+}
+
+struct pakfire_mirror* pakfire_mirrorlist_get_next(
+               struct pakfire_mirrorlist* list, struct pakfire_mirror* mirror) {
+       for (unsigned int i = 0; i < list->num_mirrors; i++) {
+               if (list->mirrors[i] == mirror) {
+                       if (i < list->num_mirrors)
+                               return list->mirrors[i+1];
+
+                       break;
+               }
+       }
+
+       return NULL;
+}
index fc488c642f6b5a8f2d4ab19a8b72493bbc151d3a..e4462aa96b57f551e43dc6fce3b2d30d67262ee7 100644 (file)
@@ -405,7 +405,7 @@ struct pakfire_mirrorlist* pakfire_repo_get_mirrorlist(struct pakfire_repo* repo
                if (!*repo->appdata->mirrorlist)
                        return NULL;
 
-               int r = pakfire_mirrorlist_create(&repo->mirrorlist, repo->pakfire);
+               int r = pakfire_mirrorlist_create(&repo->mirrorlist, repo->ctx);
                if (r) {
                        ERROR(repo->pakfire, "Could not create mirrorlist: %m\n");
                        return NULL;
@@ -525,7 +525,7 @@ static int pakfire_repo_read_metadata(struct pakfire_repo* repo, const char* pat
 
        DEBUG(repo->pakfire, "Reading repository metadata from %s...\n", path);
 
-       struct json_object* json = pakfire_json_parse_from_file(repo->pakfire, path);
+       struct json_object* json = pakfire_json_parse_from_file(repo->ctx, path);
        if (!json) {
                switch (errno) {
                        case ENOENT:
index 8f3c68a451268290b701b0ab29fc7cc4a8cad871..decef2c4772d0b2dbde172e8a3c982e7ae8d1be4 100644 (file)
@@ -46,6 +46,7 @@
 #define PCRE2_CODE_UNIT_WIDTH 8
 #include <pcre2.h>
 
+#include <pakfire/ctx.h>
 #include <pakfire/constants.h>
 #include <pakfire/logging.h>
 #include <pakfire/package.h>
@@ -737,7 +738,7 @@ int pakfire_archive_copy_data_to_buffer(struct pakfire* pakfire, struct archive*
 
 // JSON Stuff
 
-static struct json_object* pakfire_json_parse(struct pakfire* pakfire, FILE* f) {
+static struct json_object* pakfire_json_parse(struct pakfire_ctx* ctx, FILE* f) {
        struct json_tokener* tokener = NULL;
        struct json_object* json = NULL;
        char* buffer = NULL;
@@ -751,7 +752,7 @@ static struct json_object* pakfire_json_parse(struct pakfire* pakfire, FILE* f)
        // Create tokener
        tokener = json_tokener_new();
        if (!tokener) {
-               ERROR(pakfire, "Could not allocate JSON tokener: %m\n");
+               CTX_ERROR(ctx, "Could not allocate JSON tokener: %m\n");
                goto ERROR;
        }
 
@@ -760,12 +761,12 @@ static struct json_object* pakfire_json_parse(struct pakfire* pakfire, FILE* f)
        if (!json) {
                enum json_tokener_error error = json_tokener_get_error(tokener);
 
-               ERROR(pakfire, "JSON parsing error: %s\n", json_tokener_error_desc(error));
+               CTX_ERROR(ctx, "JSON parsing error: %s\n", json_tokener_error_desc(error));
                goto ERROR;
        }
 
        // Log what we have parsed
-       DEBUG(pakfire, "Parsed JSON:\n%s\n",
+       CTX_DEBUG(ctx, "Parsed JSON:\n%s\n",
                json_object_to_json_string_ext(json,
                        JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY)
        );
@@ -780,12 +781,12 @@ ERROR:
        return json;
 }
 
-struct json_object* pakfire_json_parse_from_file(struct pakfire* pakfire, const char* path) {
+struct json_object* pakfire_json_parse_from_file(struct pakfire_ctx* ctx, const char* path) {
        FILE* f = fopen(path, "r");
        if (!f)
                return NULL;
 
-       struct json_object* json = pakfire_json_parse(pakfire, f);
+       struct json_object* json = pakfire_json_parse(ctx, f);
        fclose(f);
 
        return json;