From: Michael Tremer Date: Mon, 16 Oct 2023 15:33:54 +0000 (+0000) Subject: downloader: Split mirrors and mirrorlists into their own files X-Git-Tag: 0.9.30~1485 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=46643a9b0e47a0562d448e93e6d62d480d9ebfe2;p=people%2Fms%2Fpakfire.git downloader: Split mirrors and mirrorlists into their own files Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index c75aa91e5..30c12240d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/src/libpakfire/dist.c b/src/libpakfire/dist.c index e7ebba390..bc6495713 100644 --- a/src/libpakfire/dist.c +++ b/src/libpakfire/dist.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -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); diff --git a/src/libpakfire/downloader.c b/src/libpakfire/downloader.c index a8a13a9b5..d5862b41c 100644 --- a/src/libpakfire/downloader.c +++ b/src/libpakfire/downloader.c @@ -39,21 +39,9 @@ #include #include -// 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); -} diff --git a/src/libpakfire/include/pakfire/downloader.h b/src/libpakfire/include/pakfire/downloader.h index d2a1bd1ca..0f36f95a5 100644 --- a/src/libpakfire/include/pakfire/downloader.h +++ b/src/libpakfire/include/pakfire/downloader.h @@ -24,9 +24,9 @@ #ifdef PAKFIRE_PRIVATE struct pakfire_downloader; -struct pakfire_mirrorlist; #include +#include #include 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 index 000000000..3796671d6 --- /dev/null +++ b/src/libpakfire/include/pakfire/mirror.h @@ -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 . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_MIRROR_H +#define PAKFIRE_MIRROR_H + +struct pakfire_mirror; + +#include + +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 index 000000000..9330b2300 --- /dev/null +++ b/src/libpakfire/include/pakfire/mirrorlist.h @@ -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 . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_MIRRORLIST_H +#define PAKFIRE_MIRRORLIST_H + +#ifdef PAKFIRE_PRIVATE + +struct pakfire_mirrorlist; + +#include +#include + +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 */ diff --git a/src/libpakfire/include/pakfire/util.h b/src/libpakfire/include/pakfire/util.h index 7af64b5f6..2bad16130 100644 --- a/src/libpakfire/include/pakfire/util.h +++ b/src/libpakfire/include/pakfire/util.h @@ -31,6 +31,7 @@ #define PCRE2_CODE_UNIT_WIDTH 8 #include +#include #include #include @@ -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 index 000000000..6cf40692a --- /dev/null +++ b/src/libpakfire/mirror.c @@ -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 . # +# # +#############################################################################*/ + +#include +#include + +#include +#include +#include + +// 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 index 000000000..d3b468adb --- /dev/null +++ b/src/libpakfire/mirrorlist.c @@ -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 . # +# # +#############################################################################*/ + +#include +#include + +#include +#include +#include +#include +#include + +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; +} diff --git a/src/libpakfire/repo.c b/src/libpakfire/repo.c index fc488c642..e4462aa96 100644 --- a/src/libpakfire/repo.c +++ b/src/libpakfire/repo.c @@ -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: diff --git a/src/libpakfire/util.c b/src/libpakfire/util.c index 8f3c68a45..decef2c47 100644 --- a/src/libpakfire/util.c +++ b/src/libpakfire/util.c @@ -46,6 +46,7 @@ #define PCRE2_CODE_UNIT_WIDTH 8 #include +#include #include #include #include @@ -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;