]> git.ipfire.org Git - pakfire.git/commitdiff
downloader: Parse mirrorlist
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 12 Mar 2021 11:08:57 +0000 (11:08 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 12 Mar 2021 11:09:10 +0000 (11:09 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/downloader.c

index 1e6c0c2979cf9c883fb814ede228029d0ec3c01c..d18c30057caa8dbee86843c8647683d94e393e3b 100644 (file)
@@ -25,6 +25,7 @@
 #include <utime.h>
 
 #include <curl/curl.h>
+#include <json.h>
 
 #include <pakfire/downloader.h>
 #include <pakfire/logging.h>
@@ -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,