1 /* librepo - A library providing (libcURL like) API to downloading repository
2 * Copyright (C) 2012 Tomas Mlcoch
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 //#define _POSIX_SOURCE
22 //#define _DEFAULT_SOURCE
23 #define BITS_IN_BYTE 8
24
25 #include <stdio.h>
26 #include <libgen.h>
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34
35 #ifdef WITH_ZCHUNK
36 #include <zck.h>
37 #endif /* WITH_ZCHUNK */
38
39 #include "util.h"
40 #include "metalink.h"
41 #include "repomd.h"
42 #include "downloader.h"
43 #include "handle_internal.h"
44 #include "result_internal.h"
45 #include "yum_internal.h"
46 #include "gpg.h"
47 #include "cleanup.h"
48 #include "librepo.h"
49
50 /* helper functions for YumRepo manipulation */
51
52 LrYumRepo *
lr_yum_repo_init(void)53 lr_yum_repo_init(void)
54 {
55 return lr_malloc0(sizeof(LrYumRepo));
56 }
57
58 void
lr_yum_repo_free(LrYumRepo * repo)59 lr_yum_repo_free(LrYumRepo *repo)
60 {
61 if (!repo)
62 return;
63
64 for (GSList *elem = repo->paths; elem; elem = g_slist_next(elem)) {
65 LrYumRepoPath *yumrepopath = elem->data;
66 assert(yumrepopath);
67 lr_free(yumrepopath->type);
68 lr_free(yumrepopath->path);
69 lr_free(yumrepopath);
70 }
71
72 g_slist_free(repo->paths);
73 lr_free(repo->repomd);
74 lr_free(repo->url);
75 lr_free(repo->destdir);
76 lr_free(repo->signature);
77 lr_free(repo->mirrorlist);
78 lr_free(repo->metalink);
79 lr_free(repo);
80 }
81
82 static char *
get_type(LrYumRepo * repo,const char * type)83 get_type(LrYumRepo *repo, const char *type)
84 {
85 if (!repo->use_zchunk)
86 return g_strdup(type);
87
88 gchar *chk_type = g_strconcat(type, "_zck", NULL);
89
90 for (GSList *elem = repo->paths; elem; elem = g_slist_next(elem)) {
91 LrYumRepoPath *yumrepopath = elem->data;
92 assert(yumrepopath);
93 if (!strcmp(yumrepopath->type, chk_type))
94 return chk_type;
95 }
96 g_free(chk_type);
97 return g_strdup(type);
98 }
99
100 static const char *
yum_repo_path(LrYumRepo * repo,const char * type)101 yum_repo_path(LrYumRepo *repo, const char *type)
102 {
103 assert(repo);
104
105 for (GSList *elem = repo->paths; elem; elem = g_slist_next(elem)) {
106 LrYumRepoPath *yumrepopath = elem->data;
107 assert(yumrepopath);
108 if (!strcmp(yumrepopath->type, type))
109 return yumrepopath->path;
110 }
111 return NULL;
112 }
113
114 const char *
lr_yum_repo_path(LrYumRepo * repo,const char * type)115 lr_yum_repo_path(LrYumRepo *repo, const char *type)
116 {
117 assert(repo);
118
119 gchar *chk_type = get_type(repo, type);
120 const char *path = yum_repo_path(repo, chk_type);
121 g_free(chk_type);
122 return path;
123 }
124
125 /** Append path to the repository object.
126 * @param repo Yum repo object.
127 * @param type Type of file. E.g. "primary", "filelists", ...
128 * @param path Path to the file.
129 */
130 static void
lr_yum_repo_append(LrYumRepo * repo,const char * type,const char * path)131 lr_yum_repo_append(LrYumRepo *repo, const char *type, const char *path)
132 {
133 assert(repo);
134 assert(type);
135 assert(path);
136
137 LrYumRepoPath *yumrepopath = lr_malloc(sizeof(LrYumRepoPath));
138 yumrepopath->type = g_strdup(type);
139 yumrepopath->path = g_strdup(path);
140 repo->paths = g_slist_append(repo->paths, yumrepopath);
141 }
142
143 static void
lr_yum_repo_update(LrYumRepo * repo,const char * type,const char * path)144 lr_yum_repo_update(LrYumRepo *repo, const char *type, const char *path)
145 {
146 assert(repo);
147 assert(type);
148 assert(path);
149
150 for (GSList *elem = repo->paths; elem; elem = g_slist_next(elem)) {
151 LrYumRepoPath *yumrepopath = elem->data;
152 assert(yumrepopath);
153
154 if (!strcmp(yumrepopath->type, type)) {
155 lr_free(yumrepopath->path);
156 yumrepopath->path = g_strdup(path);
157 return;
158 }
159 }
160
161 lr_yum_repo_append(repo, type, path);
162 }
163
164 /* main business logic */
165
166 gint
compare_records(gconstpointer a,gconstpointer b)167 compare_records(gconstpointer a, gconstpointer b)
168 {
169 LrYumRepoMdRecord* yum_record = (LrYumRepoMdRecord*) a;
170 char *type1 = (char *) yum_record->type;
171 char *type2 = (char *) b;
172 return g_strcmp0(type1, type2);
173 }
174
175 static void
lr_yum_switch_to_zchunk(LrHandle * handle,LrYumRepoMd * repomd)176 lr_yum_switch_to_zchunk(LrHandle *handle, LrYumRepoMd *repomd)
177 {
178 if (handle->yumdlist) {
179 int x = 0;
180 while (handle->yumdlist[x]) {
181 char *check_type = g_strconcat(handle->yumdlist[x], "_zck", NULL);
182 assert(check_type);
183
184 /* Check whether we already want the zchunk version of this record */
185 int found = FALSE;
186 int y = 0;
187 while (handle->yumdlist[y]) {
188 if (y == x) {
189 y++;
190 continue;
191 }
192 if (strcmp(handle->yumdlist[y], check_type) == 0) {
193 found = TRUE;
194 break;
195 }
196 y++;
197 }
198 if (found) {
199 g_free(check_type);
200 x++;
201 continue;
202 }
203
204 found = FALSE;
205 /* Check whether the zchunk version of this record exists */
206 for (GSList *elem = repomd->records; elem; elem = g_slist_next(elem)) {
207 LrYumRepoMdRecord *record = elem->data;
208
209 if (strcmp(record->type, check_type) == 0) {
210 g_debug("Found %s so using instead of %s", check_type,
211 handle->yumdlist[x]);
212 g_free(handle->yumdlist[x]);
213 handle->yumdlist[x] = check_type;
214 found = TRUE;
215 break;
216 }
217 }
218 if (!found)
219 g_free(check_type);
220 x++;
221 }
222 }
223 return;
224 }
225
226 static gboolean
lr_yum_repomd_record_enabled(LrHandle * handle,const char * type,GSList * records)227 lr_yum_repomd_record_enabled(LrHandle *handle, const char *type, GSList* records)
228 {
229 // Check for records that shouldn't be downloaded
230 if (handle->yumblist) {
231 int x = 0;
232 while (handle->yumblist[x]) {
233 if (!strcmp(handle->yumblist[x], type))
234 return FALSE;
235 x++;
236 }
237 }
238
239 // Check for records that should be downloaded
240 if (handle->yumdlist) {
241 int x = 0;
242 while (handle->yumdlist[x]) {
243 if (!strcmp(handle->yumdlist[x], type))
244 return TRUE;
245 x++;
246 }
247 // Substitution check
248 if (handle->yumslist) {
249 for (GSList *elem = handle->yumslist; elem; elem = g_slist_next(elem)) {
250 LrVar* subs = elem->data;
251 if (!g_strcmp0(subs->val, type)) {
252 char *orig = subs->var;
253 for (guint i = 0; handle->yumdlist[i]; i++) {
254 if (!g_strcmp0(orig, handle->yumdlist[i]) &&
255 !g_slist_find_custom(records, orig, (GCompareFunc) compare_records))
256 return TRUE;
257 }
258 return FALSE;
259 }
260 }
261 }
262 return FALSE;
263 }
264 return TRUE;
265 }
266
cbdata_new(void * userdata,void * cbdata,LrProgressCb progresscb,LrHandleMirrorFailureCb hmfcb,const char * metadata)267 static CbData *cbdata_new(void *userdata,
268 void *cbdata,
269 LrProgressCb progresscb,
270 LrHandleMirrorFailureCb hmfcb,
271 const char *metadata)
272 {
273 CbData *data = calloc(1, sizeof(*data));
274 data->userdata = userdata;
275 data->cbdata = cbdata;
276 data->progresscb = progresscb;
277 data->hmfcb = hmfcb;
278 data->metadata = g_strdup(metadata);
279 return data;
280 }
281
282 static void
cbdata_free(CbData * data)283 cbdata_free(CbData *data)
284 {
285 if (!data) return;
286 free(data->metadata);
287 free(data);
288 }
289
290 static int
progresscb(void * clientp,double total_to_download,double downloaded)291 progresscb(void *clientp, double total_to_download, double downloaded)
292 {
293 CbData *data = clientp;
294 if (data->progresscb)
295 return data->progresscb(data->userdata, total_to_download, downloaded);
296 return LR_CB_OK;
297 }
298
299 int
hmfcb(void * clientp,const char * msg,const char * url)300 hmfcb(void *clientp, const char *msg, const char *url)
301 {
302 CbData *data = clientp;
303 if (data->hmfcb)
304 return data->hmfcb(data->userdata, msg, url, data->metadata);
305 return LR_CB_OK;
306 }
307
308 gboolean
lr_prepare_repodata_dir(LrHandle * handle,GError ** err)309 lr_prepare_repodata_dir(LrHandle *handle,
310 GError **err)
311 {
312 int rc;
313 int create_repodata_dir = 1;
314 char *path_to_repodata;
315
316 path_to_repodata = lr_pathconcat(handle->destdir, "repodata", NULL);
317
318 if (handle->update) { /* Check if should create repodata/ subdir */
319 struct stat buf;
320 if (stat(path_to_repodata, &buf) != -1)
321 if (S_ISDIR(buf.st_mode))
322 create_repodata_dir = 0;
323 }
324
325 if (create_repodata_dir) {
326 /* Prepare repodata/ subdir */
327 rc = mkdir(path_to_repodata, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH);
328 if (rc == -1) {
329 g_debug("%s: Cannot create dir: %s (%s)",
330 __func__, path_to_repodata, g_strerror(errno));
331 g_set_error(err, LR_YUM_ERROR, LRE_CANNOTCREATEDIR,
332 "Cannot create directory: %s: %s",
333 path_to_repodata, g_strerror(errno));
334 lr_free(path_to_repodata);
335 return FALSE;
336 }
337 }
338 lr_free(path_to_repodata);
339
340 return TRUE;
341 }
342
343 gboolean
lr_store_mirrorlist_files(LrHandle * handle,LrYumRepo * repo,GError ** err)344 lr_store_mirrorlist_files(LrHandle *handle,
345 LrYumRepo *repo,
346 GError **err)
347 {
348 int fd;
349 int rc;
350
351 if (handle->mirrorlist_fd != -1) {
352 char *ml_file_path = lr_pathconcat(handle->destdir,
353 "mirrorlist", NULL);
354 fd = open(ml_file_path, O_CREAT|O_TRUNC|O_RDWR, 0666);
355 if (fd < 0) {
356 g_debug("%s: Cannot create: %s", __func__, ml_file_path);
357 g_set_error(err, LR_YUM_ERROR, LRE_IO,
358 "Cannot create %s: %s", ml_file_path, g_strerror(errno));
359 lr_free(ml_file_path);
360 return FALSE;
361 }
362 rc = lr_copy_content(handle->mirrorlist_fd, fd);
363 close(fd);
364 if (rc != 0) {
365 g_debug("%s: Cannot copy content of mirrorlist file", __func__);
366 g_set_error(err, LR_YUM_ERROR, LRE_IO,
367 "Cannot copy content of mirrorlist file %s: %s",
368 ml_file_path, g_strerror(errno));
369 lr_free(ml_file_path);
370 return FALSE;
371 }
372 repo->mirrorlist = ml_file_path;
373 }
374
375 return TRUE;
376 }
377
378 gboolean
lr_copy_metalink_content(LrHandle * handle,LrYumRepo * repo,GError ** err)379 lr_copy_metalink_content(LrHandle *handle,
380 LrYumRepo *repo,
381 GError **err)
382 {
383 int fd;
384 int rc;
385
386 if (handle->metalink_fd != -1) {
387 char *ml_file_path = lr_pathconcat(handle->destdir,
388 "metalink.xml", NULL);
389 fd = open(ml_file_path, O_CREAT|O_TRUNC|O_RDWR, 0666);
390 if (fd < 0) {
391 g_debug("%s: Cannot create: %s", __func__, ml_file_path);
392 g_set_error(err, LR_YUM_ERROR, LRE_IO,
393 "Cannot create %s: %s", ml_file_path, g_strerror(errno));
394 lr_free(ml_file_path);
395 return FALSE;
396 }
397 rc = lr_copy_content(handle->metalink_fd, fd);
398 close(fd);
399 if (rc != 0) {
400 g_debug("%s: Cannot copy content of metalink file", __func__);
401 g_set_error(err, LR_YUM_ERROR, LRE_IO,
402 "Cannot copy content of metalink file %s: %s",
403 ml_file_path, g_strerror(errno));
404 lr_free(ml_file_path);
405 return FALSE;
406 }
407 repo->metalink = ml_file_path;
408 }
409
410 return TRUE;
411 }
412
413 int
lr_prepare_repomd_xml_file(LrHandle * handle,char ** path,GError ** err)414 lr_prepare_repomd_xml_file(LrHandle *handle,
415 char **path,
416 GError **err)
417 {
418 int fd;
419
420 *path = lr_pathconcat(handle->destdir, "/repodata/repomd.xml", NULL);
421 fd = open(*path, O_CREAT|O_TRUNC|O_RDWR, 0666);
422 if (fd == -1) {
423 g_set_error(err, LR_YUM_ERROR, LRE_IO,
424 "Cannot open %s: %s", *path, g_strerror(errno));
425 lr_free(*path);
426 return -1;
427 }
428
429 return fd;
430 }
431
432 /** Check repomd.xml.asc if available.
433 * Try to download and verify GPG signature (repomd.xml.asc).
434 * Try to download only from the mirror where repomd.xml itself was
435 * downloaded. It is because most of yum repositories are not signed
436 * and try every mirror for signature is non effective.
437 * Every mirror would be tried because mirrored_download function have
438 * no clue if 404 for repomd.xml.asc means that no signature exists or
439 * it is just error on the mirror and should try the next one.
440 **/
441 gboolean
lr_check_repomd_xml_asc_availability(LrHandle * handle,LrYumRepo * repo,int fd,char * path,GError ** err)442 lr_check_repomd_xml_asc_availability(LrHandle *handle,
443 LrYumRepo *repo,
444 int fd,
445 char *path,
446 GError **err)
447 {
448 GError *tmp_err = NULL;
449 gboolean ret;
450
451 if (handle->checks & LR_CHECK_GPG) {
452 int fd_sig;
453 char *url, *signature;
454
455 signature = lr_pathconcat(handle->destdir, "repodata/repomd.xml.asc", NULL);
456 fd_sig = open(signature, O_CREAT | O_TRUNC | O_RDWR, 0666);
457 if (fd_sig == -1) {
458 g_debug("%s: Cannot open: %s", __func__, signature);
459 g_set_error(err, LR_YUM_ERROR, LRE_IO,
460 "Cannot open %s: %s", signature, g_strerror(errno));
461 lr_free(signature);
462 return FALSE;
463 }
464
465 url = lr_pathconcat(handle->used_mirror, "repodata/repomd.xml.asc", NULL);
466 ret = lr_download_url(handle, url, fd_sig, &tmp_err);
467 lr_free(url);
468 close(fd_sig);
469 if (!ret) {
470 // Error downloading signature
471 g_set_error(err, LR_YUM_ERROR, LRE_BADGPG,
472 "GPG verification is enabled, but GPG signature "
473 "is not available. This may be an error or the "
474 "repository does not support GPG verification: %s", tmp_err->message);
475 g_clear_error(&tmp_err);
476 unlink(signature);
477 lr_free(signature);
478 return FALSE;
479 } else {
480 // Signature downloaded
481 repo->signature = g_strdup(signature);
482 ret = lr_gpg_check_signature(signature,
483 path,
484 handle->gnupghomedir,
485 &tmp_err);
486 lr_free(signature);
487 if (!ret) {
488 g_debug("%s: GPG signature verification failed: %s",
489 __func__, tmp_err->message);
490 g_propagate_prefixed_error(err, tmp_err,
491 "repomd.xml GPG signature verification error: ");
492 return FALSE;
493 }
494 g_debug("%s: GPG signature successfully verified", __func__);
495 }
496 }
497
498 return TRUE;
499 }
500
501 void
lr_get_best_checksum(const LrMetalink * metalink,GSList ** checksums)502 lr_get_best_checksum(const LrMetalink *metalink,
503 GSList **checksums)
504 {
505 gboolean ret;
506 LrChecksumType ch_type;
507 gchar *ch_value;
508
509 // From the metalink itself
510 ret = lr_best_checksum(metalink->hashes, &ch_type, &ch_value);
511 if (ret)
512 {
513 LrDownloadTargetChecksum *dtch;
514 dtch = lr_downloadtargetchecksum_new(ch_type, ch_value);
515 *checksums = g_slist_prepend(*checksums, dtch);
516 g_debug("%s: Expected checksum for repomd.xml: (%s) %s",
517 __func__, lr_checksum_type_to_str(ch_type), ch_value);
518 }
519
520 // From the alternates entries
521 for (GSList *elem = metalink->alternates; elem; elem = g_slist_next(elem))
522 {
523 LrMetalinkAlternate *alt = elem->data;
524 ret = lr_best_checksum(alt->hashes, &ch_type, &ch_value);
525 if (ret) {
526 LrDownloadTargetChecksum *dtch;
527 dtch = lr_downloadtargetchecksum_new(ch_type, ch_value);
528 *checksums = g_slist_prepend(*checksums, dtch);
529 g_debug("%s: Expected alternate checksum for repomd.xml: (%s) %s",
530 __func__, lr_checksum_type_to_str(ch_type), ch_value);
531 }
532 }
533 }
534
535 CbData *
lr_get_metadata_failure_callback(const LrHandle * handle)536 lr_get_metadata_failure_callback(const LrHandle *handle)
537 {
538 CbData *cbdata = NULL;
539 if (handle->hmfcb) {
540 cbdata = cbdata_new(handle->user_data,
541 NULL,
542 NULL,
543 handle->hmfcb,
544 "repomd.xml");
545 }
546 return cbdata;
547 }
548
549 gboolean
lr_yum_download_url(LrHandle * lr_handle,const char * url,int fd,gboolean no_cache,gboolean is_zchunk,GError ** err)550 lr_yum_download_url(LrHandle *lr_handle, const char *url, int fd,
551 gboolean no_cache, gboolean is_zchunk, GError **err)
552 {
553 gboolean ret;
554 LrDownloadTarget *target;
555 GError *tmp_err = NULL;
556 CbData *cbdata = NULL;
557
558 assert(url);
559 assert(!err || *err == NULL);
560
561 if (lr_handle != NULL)
562 cbdata = cbdata_new(lr_handle->user_data,
563 NULL,
564 lr_handle->user_cb,
565 lr_handle->hmfcb,
566 url);
567
568 // Prepare target
569 target = lr_downloadtarget_new(lr_handle,
570 url, NULL, fd, NULL,
571 NULL, 0, 0,(lr_handle && lr_handle->user_cb) ? progresscb : NULL, cbdata,
572 NULL, (lr_handle && lr_handle->hmfcb) ? hmfcb : NULL, NULL, 0, 0,
573 NULL, no_cache, is_zchunk);
574
575 // Download the target
576 ret = lr_download_target(target, &tmp_err);
577
578 assert(ret || tmp_err);
579 assert(!(target->err) || !ret);
580 if (cbdata)
581 cbdata_free(cbdata);
582
583 if (!ret)
584 g_propagate_error(err, tmp_err);
585
586 lr_downloadtarget_free(target);
587
588 lseek(fd, 0, SEEK_SET);
589
590 return ret;
591 }
592
593 static gboolean
lr_yum_download_repomd(LrHandle * handle,LrMetalink * metalink,int fd,GError ** err)594 lr_yum_download_repomd(LrHandle *handle,
595 LrMetalink *metalink,
596 int fd,
597 GError **err)
598 {
599 int ret = TRUE;
600 GError *tmp_err = NULL;
601
602 assert(!err || *err == NULL);
603
604 g_debug("%s: Downloading repomd.xml via mirrorlist", __func__);
605
606 GSList *checksums = NULL;
607 if (metalink && (handle->checks & LR_CHECK_CHECKSUM)) {
608 lr_get_best_checksum(metalink, &checksums);
609 }
610
611 CbData *cbdata = cbdata_new(handle->user_data,
612 NULL,
613 handle->user_cb,
614 handle->hmfcb,
615 "repomd.xml");
616
617 LrDownloadTarget *target = lr_downloadtarget_new(handle,
618 "repodata/repomd.xml",
619 NULL,
620 fd,
621 NULL,
622 checksums,
623 0,
624 0,
625 (handle->user_cb) ? progresscb : NULL,
626 cbdata,
627 NULL,
628 (handle->hmfcb) ? hmfcb : NULL,
629 NULL,
630 0,
631 0,
632 NULL,
633 TRUE,
634 FALSE);
635
636 ret = lr_download_target(target, &tmp_err);
637 assert((ret && !tmp_err) || (!ret && tmp_err));
638
639 if (cbdata)
640 cbdata_free(cbdata);
641
642 if (tmp_err) {
643 g_propagate_prefixed_error(err, tmp_err,
644 "Cannot download repomd.xml: ");
645 } else if (target->err) {
646 assert(0); // This should not happen since failfast should be TRUE
647 ret = FALSE;
648 g_set_error(err, LR_DOWNLOADER_ERROR, target->rcode,
649 "Cannot download repomd.xml: %s",target->err);
650 } else {
651 // Set mirror used for download a repomd.xml to the handle
652 // TODO: Get rid of use_mirror attr
653 lr_free(handle->used_mirror);
654 handle->used_mirror = g_strdup(target->usedmirror);
655 }
656
657 lr_downloadtarget_free(target);
658
659 if (!ret) {
660 /* Download of repomd.xml was not successful */
661 g_debug("%s: repomd.xml download was unsuccessful", __func__);
662 }
663
664 return ret;
665 }
666
667 gboolean
prepare_repo_download_std_target(LrHandle * handle,LrYumRepoMdRecord * record,char ** path,int * fd,GSList ** checksums,GSList ** targets,GError ** err)668 prepare_repo_download_std_target(LrHandle *handle,
669 LrYumRepoMdRecord *record,
670 char **path,
671 int *fd,
672 GSList **checksums,
673 GSList **targets,
674 GError **err)
675 {
676 *path = lr_pathconcat(handle->destdir, record->location_href, NULL);
677 *fd = open(*path, O_CREAT|O_TRUNC|O_RDWR, 0666);
678 if (*fd < 0) {
679 g_debug("%s: Cannot create/open %s (%s)",
680 __func__, *path, g_strerror(errno));
681 g_set_error(err, LR_YUM_ERROR, LRE_IO,
682 "Cannot create/open %s: %s", *path, g_strerror(errno));
683 lr_free(*path);
684 g_slist_free_full(*targets, (GDestroyNotify) lr_downloadtarget_free);
685 return FALSE;
686 }
687
688 if (handle->checks & LR_CHECK_CHECKSUM) {
689 // Select proper checksum type only if checksum check is enabled
690 LrDownloadTargetChecksum *checksum;
691 checksum = lr_downloadtargetchecksum_new(
692 lr_checksum_type(record->checksum_type),
693 record->checksum);
694 *checksums = g_slist_prepend(*checksums, checksum);
695 }
696 return TRUE;
697 }
698
699 #ifdef WITH_ZCHUNK
700 gboolean
prepare_repo_download_zck_target(LrHandle * handle,LrYumRepoMdRecord * record,char ** path,int * fd,GSList ** checksums,GSList ** targets,GError ** err)701 prepare_repo_download_zck_target(LrHandle *handle,
702 LrYumRepoMdRecord *record,
703 char **path,
704 int *fd,
705 GSList **checksums,
706 GSList **targets,
707 GError **err)
708 {
709 *path = lr_pathconcat(handle->destdir, record->location_href, NULL);
710 *fd = open(*path, O_CREAT|O_RDWR, 0666);
711 if (*fd < 0) {
712 g_debug("%s: Cannot create/open %s (%s)",
713 __func__, *path, g_strerror(errno));
714 g_set_error(err, LR_YUM_ERROR, LRE_IO,
715 "Cannot create/open %s: %s", *path, g_strerror(errno));
716 lr_free(*path);
717 g_slist_free_full(*targets, (GDestroyNotify) lr_downloadtarget_free);
718 return FALSE;
719 }
720
721 if (handle->checks & LR_CHECK_CHECKSUM) {
722 // Select proper checksum type only if checksum check is enabled
723 LrDownloadTargetChecksum *checksum;
724 checksum = lr_downloadtargetchecksum_new(
725 lr_checksum_type(record->header_checksum_type),
726 record->header_checksum);
727 *checksums = g_slist_prepend(*checksums, checksum);
728 }
729 return TRUE;
730 }
731 #endif /* WITH_ZCHUNK */
732
733 gboolean
prepare_repo_download_targets(LrHandle * handle,LrYumRepo * repo,LrYumRepoMd * repomd,LrMetadataTarget * mdtarget,GSList ** targets,GSList ** cbdata_list,GError ** err)734 prepare_repo_download_targets(LrHandle *handle,
735 LrYumRepo *repo,
736 LrYumRepoMd *repomd,
737 LrMetadataTarget *mdtarget,
738 GSList **targets,
739 GSList **cbdata_list,
740 GError **err)
741 {
742 char *destdir; /* Destination dir */
743
744 destdir = handle->destdir;
745 assert(destdir);
746 assert(strlen(destdir));
747 assert(!err || *err == NULL);
748
749 if(handle->cachedir) {
750 lr_yum_switch_to_zchunk(handle, repomd);
751 repo->use_zchunk = TRUE;
752 } else {
753 g_debug("%s: Cache directory not set, disabling zchunk", __func__);
754 repo->use_zchunk = FALSE;
755 }
756
757 for (GSList *elem = repomd->records; elem; elem = g_slist_next(elem)) {
758 int fd;
759 char *path;
760 LrDownloadTarget *target;
761 LrYumRepoMdRecord *record = elem->data;
762 CbData *cbdata = NULL;
763 void *user_cbdata = NULL;
764 LrEndCb endcb = NULL;
765
766 if (mdtarget != NULL) {
767 user_cbdata = mdtarget->cbdata;
768 endcb = mdtarget->endcb;
769 }
770
771 assert(record);
772
773 if (!lr_yum_repomd_record_enabled(handle, record->type, repomd->records))
774 continue;
775
776 char *location_href = record->location_href;
777
778 char *dest_dir = realpath(handle->destdir, NULL);
779 path = lr_pathconcat(handle->destdir, record->location_href, NULL);
780 char *requested_dir = realpath(dirname(path), NULL);
781 lr_free(path);
782 if (!g_str_has_prefix(requested_dir, dest_dir)) {
783 g_debug("%s: Invalid path: %s", __func__, location_href);
784 g_set_error(err, LR_YUM_ERROR, LRE_IO, "Invalid path: %s", location_href);
785 g_slist_free_full(*targets, (GDestroyNotify) lr_downloadtarget_free);
786 free(requested_dir);
787 free(dest_dir);
788 return FALSE;
789 }
790 free(requested_dir);
791 free(dest_dir);
792
793 gboolean is_zchunk = FALSE;
794 #ifdef WITH_ZCHUNK
795 if (handle->cachedir && record->header_checksum)
796 is_zchunk = TRUE;
797 #endif /* WITH_ZCHUNK */
798
799 GSList *checksums = NULL;
800 if (is_zchunk) {
801 #ifdef WITH_ZCHUNK
802 if(!prepare_repo_download_zck_target(handle, record, &path, &fd,
803 &checksums, targets, err))
804 return FALSE;
805 #endif /* WITH_ZCHUNK */
806 } else {
807 if(!prepare_repo_download_std_target(handle, record, &path, &fd,
808 &checksums, targets, err))
809 return FALSE;
810 }
811
812 if (handle->user_cb || handle->hmfcb) {
813 cbdata = cbdata_new(handle->user_data,
814 user_cbdata,
815 handle->user_cb,
816 handle->hmfcb,
817 record->type);
818 *cbdata_list = g_slist_append(*cbdata_list, cbdata);
819 }
820
821 target = lr_downloadtarget_new(handle,
822 location_href,
823 record->location_base,
824 fd,
825 NULL,
826 checksums,
827 0,
828 0,
829 NULL,
830 cbdata,
831 endcb,
832 NULL,
833 NULL,
834 0,
835 0,
836 NULL,
837 FALSE,
838 is_zchunk);
839
840 if(is_zchunk) {
841 #ifdef WITH_ZCHUNK
842 target->expectedsize = record->size_header;
843 target->zck_header_size = record->size_header;
844 #endif /* WITH_ZCHUNK */
845 }
846
847 if (mdtarget != NULL)
848 mdtarget->repomd_records_to_download++;
849 *targets = g_slist_append(*targets, target);
850
851 /* Because path may already exists in repo (while update) */
852 lr_yum_repo_update(repo, record->type, path);
853 lr_free(path);
854 }
855
856 return TRUE;
857 }
858
859 gboolean
error_handling(GSList * targets,GError ** dest_error,GError * src_error)860 error_handling(GSList *targets, GError **dest_error, GError *src_error)
861 {
862 if (src_error) {
863 g_propagate_prefixed_error(dest_error, src_error,
864 "Downloading error: ");
865 return FALSE;
866 } else {
867 int code = LRE_OK;
868 char *error_summary = NULL;
869
870 for (GSList *elem = targets; elem; elem = g_slist_next(elem)) {
871 LrDownloadTarget *target = elem->data;
872 if (target->rcode != LRE_OK) {
873 if (code == LRE_OK) {
874 // First failed download target found
875 code = target->rcode;
876 error_summary = g_strconcat(target->path,
877 " - ",
878 target->err,
879 NULL);
880 } else {
881 char *tmp = error_summary;
882 error_summary = g_strconcat(error_summary,
883 "; ",
884 target->path,
885 " - ",
886 target->err,
887 NULL);
888 g_free(tmp);
889 }
890 }
891
892 close(target->fd);
893 }
894
895 if (code != LRE_OK) {
896 // At least one target failed
897 g_set_error(dest_error, LR_DOWNLOADER_ERROR, code,
898 "Downloading error(s): %s", error_summary);
899 g_free(error_summary);
900 return FALSE;
901 }
902 }
903
904 return TRUE;
905 }
906
907 gboolean
lr_yum_download_repos(GSList * targets,GError ** err)908 lr_yum_download_repos(GSList *targets,
909 GError **err)
910 {
911 gboolean ret;
912 GSList *download_targets = NULL;
913 GSList *cbdata_list = NULL;
914 GError *download_error = NULL;
915
916 for (GSList *elem = targets; elem; elem = g_slist_next(elem)) {
917 LrMetadataTarget *target = elem->data;
918
919 if (!target->handle) {
920 continue;
921 }
922
923 prepare_repo_download_targets(target->handle,
924 target->repo,
925 target->repomd,
926 target,
927 &download_targets,
928 &cbdata_list,
929 &download_error);
930 }
931
932 if (!download_targets) {
933 g_propagate_error(err, download_error);
934 return TRUE;
935 }
936
937 ret = lr_download_single_cb(download_targets,
938 FALSE,
939 (cbdata_list) ? progresscb : NULL,
940 (cbdata_list) ? hmfcb : NULL,
941 &download_error);
942
943 error_handling(download_targets, err, download_error);
944
945 g_slist_free_full(cbdata_list, (GDestroyNotify)cbdata_free);
946 g_slist_free_full(download_targets, (GDestroyNotify)lr_downloadtarget_free);
947
948 return ret;
949 }
950
951 gboolean
lr_yum_download_repo(LrHandle * handle,LrYumRepo * repo,LrYumRepoMd * repomd,GError ** err)952 lr_yum_download_repo(LrHandle *handle,
953 LrYumRepo *repo,
954 LrYumRepoMd *repomd,
955 GError **err)
956 {
957 gboolean ret = TRUE;
958 GSList *targets = NULL;
959 GSList *cbdata_list = NULL;
960 GError *tmp_err = NULL;
961
962 assert(!err || *err == NULL);
963
964 prepare_repo_download_targets(handle, repo, repomd, NULL, &targets, &cbdata_list, err);
965
966 if (!targets)
967 return TRUE;
968
969 ret = lr_download_single_cb(targets,
970 FALSE,
971 (cbdata_list) ? progresscb : NULL,
972 (cbdata_list) ? hmfcb : NULL,
973 &tmp_err);
974
975 assert((ret && !tmp_err) || (!ret && tmp_err));
976 ret = error_handling(targets, err, tmp_err);
977
978 g_slist_free_full(cbdata_list, (GDestroyNotify)cbdata_free);
979 g_slist_free_full(targets, (GDestroyNotify)lr_downloadtarget_free);
980
981 return ret;
982 }
983
984 static gboolean
lr_yum_check_checksum_of_md_record(LrYumRepoMdRecord * rec,const char * path,GError ** err)985 lr_yum_check_checksum_of_md_record(LrYumRepoMdRecord *rec,
986 const char *path,
987 GError **err)
988 {
989 int fd;
990 char *expected_checksum;
991 LrChecksumType checksum_type;
992 gboolean ret, matches;
993 gboolean is_zchunk = FALSE;
994 GError *tmp_err = NULL;
995
996 assert(!err || *err == NULL);
997
998 if (!rec || !path)
999 return TRUE;
1000
1001 #ifdef WITH_ZCHUNK
1002 if(rec->header_checksum) {
1003 expected_checksum = rec->header_checksum;
1004 checksum_type = lr_checksum_type(rec->header_checksum_type);
1005 is_zchunk = TRUE;
1006 } else {
1007 #endif /* WITH_ZCHUNK */
1008 expected_checksum = rec->checksum;
1009 checksum_type = lr_checksum_type(rec->checksum_type);
1010 #ifdef WITH_ZCHUNK
1011 }
1012 #endif /* WITH_ZCHUNK */
1013
1014 g_debug("%s: Checking checksum of %s (expected: %s [%s])",
1015 __func__, path, expected_checksum, rec->checksum_type);
1016
1017 if (!expected_checksum) {
1018 // Empty checksum - suppose it's ok
1019 g_debug("%s: No checksum in repomd", __func__);
1020 return TRUE;
1021 }
1022
1023 if (checksum_type == LR_CHECKSUM_UNKNOWN) {
1024 g_debug("%s: Unknown checksum", __func__);
1025 g_set_error(err, LR_YUM_ERROR, LRE_UNKNOWNCHECKSUM,
1026 "Unknown checksum type for %s", path);
1027 return FALSE;
1028 }
1029
1030 fd = open(path, O_RDONLY);
1031 if (fd < 0) {
1032 g_debug("%s: Cannot open %s", __func__, path);
1033 g_set_error(err, LR_YUM_ERROR, LRE_IO,
1034 "Cannot open %s: %s", path, g_strerror(errno));
1035 return FALSE;
1036 }
1037
1038 if (is_zchunk) {
1039 #ifdef WITH_ZCHUNK
1040 ret = FALSE;
1041 matches = FALSE;
1042 zckCtx *zck = lr_zck_init_read_base(expected_checksum, checksum_type,
1043 rec->size_header, fd, &tmp_err);
1044 if (!tmp_err) {
1045 if(zck_validate_data_checksum(zck) < 1) {
1046 g_set_error(&tmp_err, LR_YUM_ERROR, LRE_ZCK,
1047 "Unable to validate zchunk checksums");
1048 } else {
1049 ret = TRUE;
1050 matches = TRUE;
1051 }
1052 }
1053 if (zck)
1054 zck_free(&zck);
1055 #endif /* WITH_ZCHUNK */
1056 } else {
1057 ret = lr_checksum_fd_cmp(checksum_type,
1058 fd,
1059 expected_checksum,
1060 1,
1061 &matches,
1062 &tmp_err);
1063 }
1064
1065 close(fd);
1066
1067 assert(ret || tmp_err);
1068
1069 if (!ret) {
1070 // Checksum calculation error
1071 g_debug("%s: Checksum check %s - Error: %s",
1072 __func__, path, tmp_err->message);
1073 g_propagate_prefixed_error(err, tmp_err,
1074 "Checksum error %s: ", path);
1075 return FALSE;
1076 } else if (!matches) {
1077 g_debug("%s: Checksum check %s - Mismatch", __func__, path);
1078 g_set_error(err, LR_YUM_ERROR, LRE_BADCHECKSUM,
1079 "Checksum mismatch %s", path);
1080 return FALSE;
1081 }
1082
1083 g_debug("%s: Checksum check - Passed", __func__);
1084
1085 return TRUE;
1086 }
1087
1088 static gboolean
lr_yum_check_repo_checksums(LrYumRepo * repo,LrYumRepoMd * repomd,GError ** err)1089 lr_yum_check_repo_checksums(LrYumRepo *repo,
1090 LrYumRepoMd *repomd,
1091 GError **err)
1092 {
1093 assert(!err || *err == NULL);
1094
1095 for (GSList *elem = repomd->records; elem; elem = g_slist_next(elem)) {
1096 gboolean ret;
1097 LrYumRepoMdRecord *record = elem->data;
1098
1099 assert(record);
1100
1101 const char *path = yum_repo_path(repo, record->type);
1102
1103 ret = lr_yum_check_checksum_of_md_record(record, path, err);
1104 if (!ret)
1105 return FALSE;
1106 }
1107
1108 return TRUE;
1109 }
1110
1111 static gboolean
lr_yum_use_local_load_base(LrHandle * handle,LrResult * result,LrYumRepo * repo,LrYumRepoMd * repomd,const gchar * baseurl,GError ** err)1112 lr_yum_use_local_load_base(LrHandle *handle,
1113 LrResult *result,
1114 LrYumRepo *repo,
1115 LrYumRepoMd *repomd,
1116 const gchar *baseurl,
1117 GError **err)
1118 {
1119 gboolean ret;
1120 GError *tmp_err = NULL;
1121 _cleanup_free_ gchar *path = NULL;
1122 _cleanup_free_ gchar *sig = NULL;
1123 _cleanup_fd_close_ int fd = -1;
1124
1125 if (handle->mirrorlist_fd != -1) {
1126 // Locate mirrorlist if available.
1127 gchar *mrl_fn = lr_pathconcat(baseurl, "mirrorlist", NULL);
1128 if (g_file_test(mrl_fn, G_FILE_TEST_IS_REGULAR)) {
1129 g_debug("%s: Found local mirrorlist: %s", __func__, mrl_fn);
1130 repo->mirrorlist = mrl_fn;
1131 } else {
1132 repo->mirrorlist = NULL;
1133 lr_free(mrl_fn);
1134 }
1135 }
1136
1137 if (handle->metalink_fd != -1) {
1138 // Locate metalink.xml if available.
1139 gchar *mtl_fn = lr_pathconcat(baseurl, "metalink.xml", NULL);
1140 if (g_file_test(mtl_fn, G_FILE_TEST_IS_REGULAR)) {
1141 g_debug("%s: Found local metalink: %s", __func__, mtl_fn);
1142 repo->metalink = mtl_fn;
1143 } else {
1144 repo->metalink = NULL;
1145 lr_free(mtl_fn);
1146 }
1147 }
1148
1149 // Open repomd.xml
1150 path = lr_pathconcat(baseurl, "repodata/repomd.xml", NULL);
1151 fd = open(path, O_RDONLY);
1152 if (fd < 0) {
1153 g_debug("%s: open(%s): %s", __func__, path, g_strerror(errno));
1154 g_set_error(err, LR_YUM_ERROR, LRE_IO,
1155 "Cannot open %s: %s", path, g_strerror(errno));
1156 return FALSE;
1157 }
1158
1159 // Parse repomd.xml
1160 g_debug("%s: Parsing repomd.xml", __func__);
1161 ret = lr_yum_repomd_parse_file(repomd, fd, lr_xml_parser_warning_logger,
1162 "Repomd xml parser", &tmp_err);
1163 if (!ret) {
1164 g_debug("%s: Parsing unsuccessful: %s", __func__, tmp_err->message);
1165 g_propagate_prefixed_error(err, tmp_err,
1166 "repomd.xml parser error: ");
1167 return FALSE;
1168 }
1169
1170 // Fill result object
1171 result->destdir = g_strdup(baseurl);
1172 repo->destdir = g_strdup(baseurl);
1173 repo->repomd = g_strdup(path);
1174
1175 // Check if signature file exists
1176 sig = lr_pathconcat(baseurl, "repodata/repomd.xml.asc", NULL);
1177 if (access(sig, F_OK) == 0)
1178 repo->signature = g_strdup(sig);
1179
1180 // Signature checking
1181 if (handle->checks & LR_CHECK_GPG) {
1182
1183 if (!repo->signature) {
1184 // Signature doesn't exist
1185 g_set_error(err, LR_YUM_ERROR, LRE_BADGPG,
1186 "GPG verification is enabled, but GPG signature "
1187 "repomd.xml.asc is not available. This may be an "
1188 "error or the repository does not support GPG verification.");
1189 return FALSE;
1190 }
1191
1192 ret = lr_gpg_check_signature(repo->signature,
1193 repo->repomd,
1194 handle->gnupghomedir,
1195 &tmp_err);
1196 if (!ret) {
1197 g_debug("%s: repomd.xml GPG signature verification failed: %s",
1198 __func__, tmp_err->message);
1199 g_propagate_prefixed_error(err, tmp_err,
1200 "repomd.xml GPG signature verification failed: ");
1201 return FALSE;
1202 }
1203 }
1204
1205 // Done - repomd is loaded and checked
1206 g_debug("%s: Repomd revision: %s", __func__, repomd->revision);
1207
1208 return TRUE;
1209 }
1210
1211 /* Do not duplicate repoata, just locate the local one */
1212 static gboolean
lr_yum_use_local(LrHandle * handle,LrResult * result,GError ** err)1213 lr_yum_use_local(LrHandle *handle, LrResult *result, GError **err)
1214 {
1215 char *baseurl;
1216 LrYumRepo *repo;
1217 LrYumRepoMd *repomd;
1218
1219 assert(!err || *err == NULL);
1220
1221 g_debug("%s: Locating repo..", __func__);
1222
1223 // Shortcuts
1224 repo = result->yum_repo;
1225 repomd = result->yum_repomd;
1226 baseurl = handle->urls[0];
1227
1228 // Skip "file://" prefix if present
1229 if (g_str_has_prefix(baseurl, "file://"))
1230 baseurl += 7;
1231 else if (g_str_has_prefix(baseurl, "file:"))
1232 baseurl += 5;
1233
1234 // Check sanity
1235 if (strstr(baseurl, "://")) {
1236 g_set_error(err, LR_YUM_ERROR, LRE_NOTLOCAL,
1237 "URL: %s doesn't seem to be a local repository",
1238 baseurl);
1239 return FALSE;
1240 }
1241
1242 if (!handle->update) {
1243 // Load repomd.xml and mirrorlist+metalink if locally available
1244 if (!lr_yum_use_local_load_base(handle, result, repo, repomd, baseurl, err))
1245 return FALSE;
1246 }
1247
1248 if(handle->cachedir) {
1249 lr_yum_switch_to_zchunk(handle, repomd);
1250 repo->use_zchunk = TRUE;
1251 } else {
1252 g_debug("%s: Cache directory not set, disabling zchunk", __func__);
1253 repo->use_zchunk = FALSE;
1254 }
1255
1256 // Locate rest of metadata files
1257 for (GSList *elem = repomd->records; elem; elem = g_slist_next(elem)) {
1258 _cleanup_free_ char *path = NULL;
1259 LrYumRepoMdRecord *record = elem->data;
1260
1261 assert(record);
1262
1263 if (!lr_yum_repomd_record_enabled(handle, record->type, repomd->records))
1264 continue; // Caller isn't interested in this record type
1265 if (yum_repo_path(repo, record->type))
1266 continue; // This path already exists in repo
1267
1268 path = lr_pathconcat(baseurl, record->location_href, NULL);
1269
1270 if (access(path, F_OK) == -1) {
1271 // A repo file is missing
1272 if (!handle->ignoremissing) {
1273 g_debug("%s: Incomplete repository - %s is missing",
1274 __func__, path);
1275 g_set_error(err, LR_YUM_ERROR, LRE_INCOMPLETEREPO,
1276 "Incomplete repository - %s is missing",
1277 path);
1278 return FALSE;
1279 }
1280
1281 continue;
1282 }
1283
1284 lr_yum_repo_append(repo, record->type, path);
1285 }
1286
1287 g_debug("%s: Repository was successfully located", __func__);
1288 return TRUE;
1289 }
1290
1291 static gboolean
lr_yum_download_remote(LrHandle * handle,LrResult * result,GError ** err)1292 lr_yum_download_remote(LrHandle *handle, LrResult *result, GError **err)
1293 {
1294 gboolean ret = TRUE;
1295 int fd;
1296 LrYumRepo *repo;
1297 LrYumRepoMd *repomd;
1298 GError *tmp_err = NULL;
1299
1300 assert(!err || *err == NULL);
1301
1302 repo = result->yum_repo;
1303 repomd = result->yum_repomd;
1304
1305 g_debug("%s: Downloading/Copying repo..", __func__);
1306
1307 if (!lr_prepare_repodata_dir(handle, err))
1308 return FALSE;
1309
1310 if (!handle->update) {
1311 char *path = NULL;
1312
1313 if (!lr_store_mirrorlist_files(handle, repo, err))
1314 return FALSE;
1315
1316 if (!lr_copy_metalink_content(handle, repo, err))
1317 return FALSE;
1318
1319 if ((fd = lr_prepare_repomd_xml_file(handle, &path, err)) == -1)
1320 return FALSE;
1321
1322 /* Download repomd.xml */
1323 ret = lr_yum_download_repomd(handle, handle->metalink, fd, err);
1324 if (!ret) {
1325 close(fd);
1326 lr_free(path);
1327 return FALSE;
1328 }
1329
1330 if (!lr_check_repomd_xml_asc_availability(handle, repo, fd, path, err)) {
1331 close(fd);
1332 lr_free(path);
1333 return FALSE;
1334 }
1335
1336 lseek(fd, 0, SEEK_SET);
1337
1338 /* Parse repomd */
1339 g_debug("%s: Parsing repomd.xml", __func__);
1340 ret = lr_yum_repomd_parse_file(repomd, fd, lr_xml_parser_warning_logger,
1341 "Repomd xml parser", &tmp_err);
1342 close(fd);
1343 if (!ret) {
1344 g_debug("%s: Parsing unsuccessful: %s", __func__, tmp_err->message);
1345 g_propagate_prefixed_error(err, tmp_err,
1346 "repomd.xml parser error: ");
1347 lr_free(path);
1348 return FALSE;
1349 }
1350
1351 /* Fill result object */
1352 result->destdir = g_strdup(handle->destdir);
1353 repo->destdir = g_strdup(handle->destdir);
1354 repo->repomd = path;
1355 if (handle->used_mirror)
1356 repo->url = g_strdup(handle->used_mirror);
1357 else
1358 repo->url = g_strdup(handle->urls[0]);
1359
1360 g_debug("%s: Repomd revision: %s", repomd->revision, __func__);
1361 }
1362
1363 /* Download rest of metadata files */
1364 ret = lr_yum_download_repo(handle, repo, repomd, &tmp_err);
1365 assert((ret && !tmp_err) || (!ret && tmp_err));
1366
1367 if (!ret) {
1368 g_debug("%s: Repository download error: %s", __func__, tmp_err->message);
1369 g_propagate_prefixed_error(err, tmp_err, "Yum repo downloading error: ");
1370 return FALSE;
1371 }
1372
1373 return TRUE;
1374 }
1375
1376 gboolean
lr_yum_perform(LrHandle * handle,LrResult * result,GError ** err)1377 lr_yum_perform(LrHandle *handle, LrResult *result, GError **err)
1378 {
1379 int ret = TRUE;
1380 LrYumRepo *repo;
1381 LrYumRepoMd *repomd;
1382
1383 assert(handle);
1384 assert(!err || *err == NULL);
1385
1386 if (!result) {
1387 g_set_error(err, LR_YUM_ERROR, LRE_BADFUNCARG,
1388 "Missing result parameter");
1389 return FALSE;
1390 }
1391
1392 if (!handle->urls && !handle->mirrorlisturl && !handle->metalinkurl) {
1393 g_set_error(err, LR_YUM_ERROR, LRE_NOURL,
1394 "No LRO_URLS, LRO_MIRRORLISTURL nor LRO_METALINKURL specified");
1395 return FALSE;
1396 }
1397
1398 if (handle->local && (!handle->urls || !handle->urls[0])) {
1399 g_set_error(err, LR_YUM_ERROR, LRE_NOURL,
1400 "Localrepo specified, but no LRO_URLS set");
1401 return FALSE;
1402 }
1403
1404 if (handle->update) {
1405 // Download/Locate only specified files
1406 if (!result->yum_repo || !result->yum_repomd) {
1407 g_set_error(err, LR_YUM_ERROR, LRE_INCOMPLETERESULT,
1408 "Incomplete result object - "
1409 "Cannot update on this result object");
1410 return FALSE;
1411 }
1412 } else {
1413 // Download/Locate from scratch
1414 if (result->yum_repo || result->yum_repomd) {
1415 g_set_error(err, LR_YUM_ERROR, LRE_ALREADYUSEDRESULT,
1416 "This result object is not clear - "
1417 "Already used result object");
1418 return FALSE;
1419 }
1420 result->yum_repo = lr_yum_repo_init();
1421 result->yum_repomd = lr_yum_repomd_init();
1422 }
1423
1424 repo = result->yum_repo;
1425 repomd = result->yum_repomd;
1426
1427 if (handle->local) {
1428 // Do not duplicate repository, just use the existing local one
1429
1430 ret = lr_yum_use_local(handle, result, err);
1431 if (!ret)
1432 return FALSE;
1433
1434 if (handle->checks & LR_CHECK_CHECKSUM)
1435 ret = lr_yum_check_repo_checksums(repo, repomd, err);
1436 } else {
1437 // Download remote/Duplicate local repository
1438 // Note: All checksums are checked while downloading
1439
1440 ret = lr_yum_download_remote(handle, result, err);
1441 }
1442
1443 return ret;
1444 }
1445