#include <utime.h>
#include <curl/curl.h>
+#include <json.h>
#include <pakfire/downloader.h>
#include <pakfire/logging.h>
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);
}
// 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);
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,