From: Michael Tremer Date: Fri, 12 Mar 2021 11:08:57 +0000 (+0000) Subject: downloader: Parse mirrorlist X-Git-Tag: 0.9.28~1285^2~556 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4f9f54ad70550af02b8eedc99a92580cde027220;p=pakfire.git downloader: Parse mirrorlist Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/downloader.c b/src/libpakfire/downloader.c index 1e6c0c297..d18c30057 100644 --- a/src/libpakfire/downloader.c +++ b/src/libpakfire/downloader.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -98,6 +99,17 @@ static int pakfire_downloader_setup_curl(struct pakfire_downloader* downloader) return 0; } +static void pakfire_downloader_clear_mirrors(struct pakfire_downloader* downloader) { + if (downloader->mirrors) { + for (unsigned int i = 0; i < downloader->num_mirrors; i++) { + free(downloader->mirrors[i]); + } + + free(downloader->mirrors); + downloader->num_mirrors = 0; + } +} + static void pakfire_transfer_free(struct pakfire_transfer* transfer) { if (transfer->handle) curl_easy_cleanup(transfer->handle); @@ -118,11 +130,7 @@ static void pakfire_downloader_free(struct pakfire_downloader* downloader) { } // Free mirrors - if (downloader->mirrors) { - for (unsigned int i = 0; i < downloader->num_mirrors; i++) - free(downloader->mirrors[i]); - free(downloader->mirrors); - } + pakfire_downloader_clear_mirrors(downloader); if (downloader->curl) curl_multi_cleanup(downloader->curl); @@ -210,17 +218,146 @@ static void pakfire_downloader_mirrors_sort(struct pakfire_downloader* downloade pakfire_downloader_mirrors_cmp); } +static int pakfire_downloader_check_mirrorlist(struct pakfire_downloader* downloader, + struct json_object* root) { + struct json_object* typeobj = NULL; + int r = 1; + + r = json_object_object_get_ex(root, "type", &typeobj); + if (r == FALSE) { + ERROR(downloader->pakfire, "mirrorlist does not have a 'type' attribute\n"); + goto ERROR; + } + + const char* type = json_object_get_string(typeobj); + if (!type) { + ERROR(downloader->pakfire, "mirrorlist has an empty or unknown 'type' attribute\n"); + goto ERROR; + } + + if (strcmp(type, "mirrorlist") != 0) { + ERROR(downloader->pakfire, "Unexpected type: %s\n", type); + goto ERROR; + } + + // Success + r = 0; + +ERROR: + if (typeobj) + json_object_put(typeobj); + + return r; +} + int pakfire_downloader_read_mirrorlist(struct pakfire_downloader* downloader, const char* path) { DEBUG(downloader->pakfire, "Reading mirrorlist from %s\n", path); + FILE* f = NULL; + struct json_object* root = NULL; + struct json_object* mirrors = NULL; + char* buffer = NULL; + size_t length; + int r = 1; + + // Create tokener + struct json_tokener* tokener = json_tokener_new(); + if (!tokener) { + ERROR(downloader->pakfire, "Could not allocate JSON tokener: %s\n", strerror(errno)); + goto ERROR; + } + + // Read file into buffer + f = fopen(path, "r"); + if (!f) + goto ERROR; + + r = pakfire_read_file_into_buffer(f, &buffer, &length); + if (r) + goto ERROR; + + // Fail if content was empty + if (!length) { + ERROR(downloader->pakfire, "%s is empty\n", path); + errno = EINVAL; + goto ERROR; + } + // Parse JSON from path + root = json_tokener_parse_ex(tokener, buffer, length); + if (!root) { + enum json_tokener_error error = json_tokener_get_error(tokener); + + ERROR(downloader->pakfire, "JSON parsing error: %s\n", + json_tokener_error_desc(error)); + r = 1; + goto ERROR; + } + +#ifdef ENABLE_DEBUG + const char* parsed_json = json_object_to_json_string_ext(root, + JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY); + DEBUG(downloader->pakfire, "Parsed JSON:\n%s\n", parsed_json); +#endif + + // Check if we found a valid mirrorlist + r = pakfire_downloader_check_mirrorlist(downloader, root); + if (r) + goto ERROR; // Clear all existing mirrors + pakfire_downloader_clear_mirrors(downloader); // Add the new mirrors + r = json_object_object_get_ex(root, "mirrors", &mirrors); + if (r == FALSE) { + DEBUG(downloader->pakfire, "Mirrorlist has no mirrors\n"); + r = 0; + goto ERROR; + } - return 0; + 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 == FALSE) + goto NEXT; + + const char* url = json_object_get_string(urlobj); + + // Add the mirror to the downloader + r = pakfire_downloader_add_mirror(downloader, url, i); + if (r) { + ERROR(downloader->pakfire, "Could not add mirror %s: %s\n", + url, strerror(errno)); + goto NEXT; + } + +NEXT: + json_object_put(mirror); + } + + // Success + r = 0; + +ERROR: + if (mirrors) + json_object_put(mirrors); + if (root) + json_object_put(root); + json_tokener_free(tokener); + + if (f) + fclose(f); + + return r; } int pakfire_downloader_add_mirror(struct pakfire_downloader* downloader,