1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * Copyright (C) 2012-2015 Red Hat, Inc.
4  * Copyright (C) 2013-2015 Richard Hughes <richard@hughsie.com>
5  *
6  * Licensed under the GNU Lesser General Public License Version 2.1
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or(at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
21  */
22 
23 /**
24  * SECTION:dnf-sack
25  * @short_description: A package sack
26  * @include: libdnf.h
27  * @stability: Unstable
28  *
29  * Sacks are repositories of packages.
30  *
31  * See also: #DnfContext
32  */
33 
34 
35 #include <algorithm>
36 #include <assert.h>
37 #include <errno.h>
38 #include <functional>
39 #include <unistd.h>
40 #include <iostream>
41 #include <list>
42 #include <set>
43 
44 extern "C" {
45 #include <solv/evr.h>
46 #include <solv/pool.h>
47 #include <solv/poolarch.h>
48 #include <solv/repo.h>
49 #include <solv/repo_deltainfoxml.h>
50 #include <solv/repo_repomdxml.h>
51 #include <solv/repo_updateinfoxml.h>
52 #include <solv/repo_rpmmd.h>
53 #include <solv/repo_rpmdb.h>
54 #include <solv/repo_solv.h>
55 #include <solv/repo_write.h>
56 #include <solv/solv_xfopen.h>
57 #include <solv/solver.h>
58 }
59 
60 #include <cstring>
61 #include <sstream>
62 
63 #include "catch-error.hpp"
64 #include "dnf-context.hpp"
65 #include "dnf-types.h"
66 #include "dnf-package.h"
67 #include "hy-iutil-private.hpp"
68 #include "hy-query.h"
69 #include "hy-repo-private.hpp"
70 #include "dnf-sack-private.hpp"
71 #include "hy-util.h"
72 
73 #include "utils/bgettext/bgettext-lib.h"
74 
75 #include "sack/query.hpp"
76 #include "nevra.hpp"
77 #include "conf/ConfigParser.hpp"
78 #include "conf/OptionBool.hpp"
79 #include "module/ModulePackageContainer.hpp"
80 #include "module/ModulePackage.hpp"
81 #include "repo/Repo-private.hpp"
82 #include "repo/solvable/DependencyContainer.hpp"
83 #include "utils/crypto/sha1.hpp"
84 #include "utils/File.hpp"
85 #include "utils/utils.hpp"
86 #include "log.hpp"
87 #include "tinyformat/tinyformat.hpp"
88 
89 
90 #define DEFAULT_CACHE_ROOT "/var/cache/hawkey"
91 #define DEFAULT_CACHE_USER "/var/tmp/hawkey"
92 
93 typedef struct
94 {
95     Id                   running_kernel_id;
96     Map                 *pkg_excludes;
97     Map                 *pkg_includes;
98     Map                 *repo_excludes;
99     Map                 *module_excludes;
100     Map                 *module_includes;   /* To fast identify enabled modular packages */
101     Map                 *pkg_solvables;     /* Map representing only solvable pkgs of query */
102     int                  pool_nsolvables;   /* Number of nsolvables for creation of pkg_solvables*/
103     Pool                *pool;
104     Queue                installonly;
105     Repo                *cmdline_repo;
106     gboolean             considered_uptodate;
107     gboolean             have_set_arch;
108     gboolean             all_arch;
109     gboolean             provides_ready;
110     gboolean             allow_vendor_change;
111     gchar               *cache_dir;
112     char                *arch;
113     dnf_sack_running_kernel_fn_t  running_kernel_fn;
114     guint                installonly_limit;
115     libdnf::ModulePackageContainer * moduleContainer;
116 } DnfSackPrivate;
117 
G_DEFINE_TYPE_WITH_PRIVATE(DnfSack,dnf_sack,G_TYPE_OBJECT)118 G_DEFINE_TYPE_WITH_PRIVATE(DnfSack, dnf_sack, G_TYPE_OBJECT)
119 #define GET_PRIVATE(o) (static_cast<DnfSackPrivate *>(dnf_sack_get_instance_private (o)))
120 
121 
122 /**
123  * dnf_sack_finalize:
124  **/
125 static void
126 dnf_sack_finalize(GObject *object)
127 {
128     DnfSack *sack = DNF_SACK(object);
129     DnfSackPrivate *priv = GET_PRIVATE(sack);
130     Pool *pool = priv->pool;
131     Repo *repo;
132     int i;
133 
134     FOR_REPOS(i, repo) {
135         auto hrepo = static_cast<HyRepo>(repo->appdata);
136         if (!hrepo)
137             continue;
138         libdnf::repoGetImpl(hrepo)->detachLibsolvRepo();
139     }
140     g_free(priv->cache_dir);
141     g_free(priv->arch);
142     queue_free(&priv->installonly);
143 
144     free_map_fully(priv->pkg_excludes);
145     free_map_fully(priv->pkg_includes);
146     free_map_fully(priv->repo_excludes);
147     free_map_fully(priv->module_excludes);
148     free_map_fully(priv->module_includes);
149     free_map_fully(pool->considered);
150     free_map_fully(priv->pkg_solvables);
151     pool_free(priv->pool);
152     if (priv->moduleContainer) {
153         delete priv->moduleContainer;
154     }
155 
156     G_OBJECT_CLASS(dnf_sack_parent_class)->finalize(object);
157 }
158 
159 // log levels (see also SOLV_ERROR etc. in <solv/pool.h>)
160 #define HY_LL_INFO  (1 << 20)
161 #define HY_LL_ERROR (1 << 21)
162 
163 static void
log_cb(Pool * pool,void * cb_data,int level,const char * buf)164 log_cb(Pool *pool, void *cb_data, int level, const char *buf)
165 {
166     /* just proxy this to the GLib logging handler */
167     switch(level) {
168         case HY_LL_INFO:
169             g_debug ("%s", buf);
170             break;
171         case HY_LL_ERROR:
172             g_warning ("%s", buf);
173             break;
174         default:
175             g_info ("%s", buf);
176             break;
177     }
178 }
179 
180 /**
181  * dnf_sack_init:
182  **/
183 static void
dnf_sack_init(DnfSack * sack)184 dnf_sack_init(DnfSack *sack)
185 {
186     DnfSackPrivate *priv = GET_PRIVATE(sack);
187     priv->pool = pool_create();
188     pool_set_flag(priv->pool, POOL_FLAG_WHATPROVIDESWITHDISABLED, 1);
189     priv->running_kernel_id = -1;
190     priv->running_kernel_fn = running_kernel;
191     priv->considered_uptodate = TRUE;
192     priv->cmdline_repo = NULL;
193     priv->allow_vendor_change = TRUE;
194     queue_init(&priv->installonly);
195 
196     /* logging up after this*/
197     pool_setdebugcallback(priv->pool, log_cb, sack);
198     pool_setdebugmask(priv->pool,
199                       SOLV_ERROR | SOLV_FATAL | SOLV_WARN | SOLV_DEBUG_RESULT |
200                       HY_LL_INFO | HY_LL_ERROR);
201 }
202 
203 /**
204  * dnf_sack_class_init:
205  **/
206 static void
dnf_sack_class_init(DnfSackClass * klass)207 dnf_sack_class_init(DnfSackClass *klass)
208 {
209     GObjectClass *object_class = G_OBJECT_CLASS(klass);
210     object_class->finalize = dnf_sack_finalize;
211 }
212 
213 /**
214  * dnf_sack_new:
215  *
216  * Creates a new #DnfSack.
217  *
218  * Returns:(transfer full): a #DnfSack
219  *
220  * Since: 0.7.0
221  **/
222 DnfSack *
dnf_sack_new(void)223 dnf_sack_new(void)
224 {
225     return DNF_SACK(g_object_new(DNF_TYPE_SACK, NULL));
226 }
227 
228 static int
can_use_repomd_cache(FILE * fp_solv,unsigned char cs_repomd[CHKSUM_BYTES])229 can_use_repomd_cache(FILE *fp_solv, unsigned char cs_repomd[CHKSUM_BYTES])
230 {
231     unsigned char cs_cache[CHKSUM_BYTES];
232 
233     if (fp_solv &&
234         !checksum_read(cs_cache, fp_solv) &&
235         !checksum_cmp(cs_cache, cs_repomd))
236         return 1;
237 
238     return 0;
239 }
240 
241 void
dnf_sack_set_running_kernel_fn(DnfSack * sack,dnf_sack_running_kernel_fn_t fn)242 dnf_sack_set_running_kernel_fn (DnfSack *sack, dnf_sack_running_kernel_fn_t fn)
243 {
244     DnfSackPrivate *priv = GET_PRIVATE(sack);
245     priv->running_kernel_fn = fn;
246 }
247 
248 void
dnf_sack_set_pkg_solvables(DnfSack * sack,Map * pkg_solvables,int pool_nsolvables)249 dnf_sack_set_pkg_solvables(DnfSack *sack, Map *pkg_solvables, int pool_nsolvables)
250 {
251     DnfSackPrivate *priv = GET_PRIVATE(sack);
252 
253     auto pkg_solvables_tmp = static_cast<Map *>(g_malloc(sizeof(Map)));
254     if (priv->pkg_solvables)
255         free_map_fully(priv->pkg_solvables);
256     map_init_clone(pkg_solvables_tmp, pkg_solvables);
257     priv->pkg_solvables = pkg_solvables_tmp;
258     priv->pool_nsolvables = pool_nsolvables;
259 }
260 
261 int
dnf_sack_get_pool_nsolvables(DnfSack * sack)262 dnf_sack_get_pool_nsolvables(DnfSack *sack)
263 {
264     DnfSackPrivate *priv = GET_PRIVATE(sack);
265     return priv->pool_nsolvables;
266 }
267 
268 libdnf::PackageSet *
dnf_sack_get_pkg_solvables(DnfSack * sack)269 dnf_sack_get_pkg_solvables(DnfSack *sack)
270 {
271     DnfSackPrivate *priv = GET_PRIVATE(sack);
272     return new libdnf::PackageSet(sack, priv->pkg_solvables);
273 }
274 
275 /**
276  * dnf_sack_last_solvable: (skip)
277  * @sack: a #DnfSack instance.
278  *
279  * Returns an ID of last solvable in sack
280  *
281  * Returns: an #Id
282  *
283  * Since: 0.7.0
284  */
285 Id
dnf_sack_last_solvable(DnfSack * sack)286 dnf_sack_last_solvable(DnfSack *sack)
287 {
288     return dnf_sack_get_pool(sack)->nsolvables - 1;
289 }
290 
291 void
dnf_sack_recompute_considered_map(DnfSack * sack,Map ** considered,libdnf::Query::ExcludeFlags flags)292 dnf_sack_recompute_considered_map(DnfSack * sack, Map ** considered, libdnf::Query::ExcludeFlags flags)
293 {
294     DnfSackPrivate *priv = GET_PRIVATE(sack);
295     Pool *pool = dnf_sack_get_pool(sack);
296     if (!*considered) {
297         if ((static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_REGULAR_EXCLUDES) ||
298             (!priv->repo_excludes && !priv->pkg_excludes && !priv->pkg_includes))
299             && (static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_MODULAR_EXCLUDES)
300             || !priv->module_excludes)) {
301             return;
302         }
303         *considered = static_cast<Map *>(g_malloc0(sizeof(Map)));
304         map_init(*considered, pool->nsolvables);
305     } else
306         map_grow(*considered, pool->nsolvables);
307 
308     // considered = (all - repo_excludes - pkg_excludes) and
309     //              (pkg_includes + all_from_repos_not_using_includes)
310     map_setall(*considered);
311     dnf_sack_make_provides_ready(sack);
312     if (!static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_MODULAR_EXCLUDES)
313         && priv->module_excludes)
314         map_subtract(*considered, priv->module_excludes);
315     if (!static_cast<bool>(flags & libdnf::Query::ExcludeFlags::IGNORE_REGULAR_EXCLUDES)) {
316         if (priv->repo_excludes)
317             map_subtract(*considered, priv->repo_excludes);
318         if (priv->pkg_excludes)
319             map_subtract(*considered, priv->pkg_excludes);
320         if (priv->pkg_includes) {
321             map_grow(priv->pkg_includes, pool->nsolvables);
322             Map pkg_includes_tmp;
323             map_init_clone(&pkg_includes_tmp, priv->pkg_includes);
324 
325             // Add all solvables from repositories which do not use "includes"
326             Id repoid;
327             Repo *repo;
328             FOR_REPOS(repoid, repo) {
329                 auto hyrepo = static_cast<HyRepo>(repo->appdata);
330                 if (!hyrepo->getUseIncludes()) {
331                     Id solvableid;
332                     Solvable *solvable;
333                     FOR_REPO_SOLVABLES(repo, solvableid, solvable)
334                         MAPSET(&pkg_includes_tmp, solvableid);
335                 }
336             }
337 
338             map_and(*considered, &pkg_includes_tmp);
339             map_free(&pkg_includes_tmp);
340         }
341     }
342 }
343 
344 /**
345  * dnf_sack_recompute_considered:
346  * @sack: a #DnfSack instance.
347  *
348  * Recompute considered packages for libsolv and queries.
349  *
350  * Since: 0.7.0
351  */
352 void
dnf_sack_recompute_considered(DnfSack * sack)353 dnf_sack_recompute_considered(DnfSack *sack)
354 {
355     DnfSackPrivate *priv = GET_PRIVATE(sack);
356     Pool *pool = dnf_sack_get_pool(sack);
357     if (priv->considered_uptodate)
358         return;
359     dnf_sack_recompute_considered_map(
360         sack, &pool->considered, libdnf::Query::ExcludeFlags::APPLY_EXCLUDES);
361     priv->considered_uptodate = TRUE;
362 }
363 
364 static gboolean
load_ext(DnfSack * sack,HyRepo hrepo,_hy_repo_repodata which_repodata,const char * suffix,const char * which_filename,int (* cb)(Repo *,FILE *),GError ** error)365 load_ext(DnfSack *sack, HyRepo hrepo, _hy_repo_repodata which_repodata,
366          const char *suffix, const char * which_filename,
367          int (*cb)(Repo *, FILE *), GError **error)
368 {
369     DnfSackPrivate *priv = GET_PRIVATE(sack);
370     int ret = 0;
371     auto repoImpl = libdnf::repoGetImpl(hrepo);
372     Repo *repo = repoImpl->libsolvRepo;
373     const char *name = repo->name;
374     FILE *fp;
375     gboolean done = FALSE;
376 
377     char *fn_cache =  dnf_sack_give_cache_fn(sack, name, suffix);
378     fp = fopen(fn_cache, "r");
379     assert(libdnf::repoGetImpl(hrepo)->checksum);
380     if (can_use_repomd_cache(fp, libdnf::repoGetImpl(hrepo)->checksum)) {
381         int flags = 0;
382         /* the updateinfo is not a real extension */
383         if (which_repodata != _HY_REPODATA_UPDATEINFO)
384             flags |= REPO_EXTEND_SOLVABLES;
385         /* do not pollute the main pool with directory component ids */
386         if (which_repodata == _HY_REPODATA_FILENAMES || which_repodata == _HY_REPODATA_OTHER)
387             flags |= REPO_LOCALPOOL;
388         done = TRUE;
389         g_debug("%s: using cache file: %s", __func__, fn_cache);
390         ret = repo_add_solv(repo, fp, flags);
391         if (ret) {
392             g_set_error_literal (error,
393                                  DNF_ERROR,
394                                  DNF_ERROR_INTERNAL_ERROR,
395                                  _("failed to add solv"));
396             return FALSE;
397         } else {
398             repo_update_state(hrepo, which_repodata, _HY_LOADED_CACHE);
399             repo_set_repodata(hrepo, which_repodata, repo->nrepodata - 1);
400         }
401     }
402     g_free(fn_cache);
403     if (fp)
404         fclose(fp);
405     if (done)
406         return TRUE;
407 
408     auto fn = hrepo->getMetadataPath(which_filename);
409     /* nothing set */
410     if (fn.empty()) {
411         g_set_error (error,
412                      DNF_ERROR,
413                      DNF_ERROR_NO_CAPABILITY,
414                      _("no %1$s string for %2$s"),
415                      which_filename, name);
416         return FALSE;
417     }
418 
419     fp = solv_xfopen(fn.c_str(), "r");
420     if (fp == NULL) {
421         g_set_error (error,
422                      DNF_ERROR,
423                      DNF_ERROR_FILE_INVALID,
424                      _("failed to open: %s"), fn.c_str());
425         return FALSE;
426     }
427     g_debug("%s: loading: %s", __func__, fn.c_str());
428 
429     int previous_last = repo->nrepodata - 1;
430     ret = cb(repo, fp);
431     fclose(fp);
432     if (ret == 0) {
433         repo_update_state(hrepo, which_repodata, _HY_LOADED_FETCH);
434         assert(previous_last == repo->nrepodata - 2); (void)previous_last;
435         repo_set_repodata(hrepo, which_repodata, repo->nrepodata - 1);
436     }
437     priv->provides_ready = 0;
438     return TRUE;
439 }
440 
441 static int
load_filelists_cb(Repo * repo,FILE * fp)442 load_filelists_cb(Repo *repo, FILE *fp)
443 {
444     if (repo_add_rpmmd(repo, fp, "FL", REPO_EXTEND_SOLVABLES))
445         return DNF_ERROR_INTERNAL_ERROR;
446     return 0;
447 }
448 
449 static int
load_presto_cb(Repo * repo,FILE * fp)450 load_presto_cb(Repo *repo, FILE *fp)
451 {
452     if (repo_add_deltainfoxml(repo, fp, 0))
453         return DNF_ERROR_INTERNAL_ERROR;
454     return 0;
455 }
456 
457 static int
load_updateinfo_cb(Repo * repo,FILE * fp)458 load_updateinfo_cb(Repo *repo, FILE *fp)
459 {
460     if (repo_add_updateinfoxml(repo, fp, 0))
461         return DNF_ERROR_INTERNAL_ERROR;
462     return 0;
463 }
464 
465 static int
load_other_cb(Repo * repo,FILE * fp)466 load_other_cb(Repo *repo, FILE *fp)
467 {
468     if (repo_add_rpmmd(repo, fp, 0, REPO_EXTEND_SOLVABLES))
469         return DNF_ERROR_INTERNAL_ERROR;
470     return 0;
471 }
472 
473 static int
repo_is_one_piece(Repo * repo)474 repo_is_one_piece(Repo *repo)
475 {
476     int i;
477     for (i = repo->start; i < repo->end; i++)
478         if (repo->pool->solvables[i].repo != repo)
479             return 0;
480     return 1;
481 }
482 
483 static gboolean
write_main(DnfSack * sack,HyRepo hrepo,int switchtosolv,GError ** error)484 write_main(DnfSack *sack, HyRepo hrepo, int switchtosolv, GError **error)
485 {
486     auto repoImpl = libdnf::repoGetImpl(hrepo);
487     Repo *repo = repoImpl->libsolvRepo;
488     const char *name = repo->name;
489     const char *chksum = pool_checksum_str(dnf_sack_get_pool(sack), repoImpl->checksum);
490     char *fn = dnf_sack_give_cache_fn(sack, name, NULL);
491     char *tmp_fn_templ = solv_dupjoin(fn, ".XXXXXX", NULL);
492     int tmp_fd  = mkstemp(tmp_fn_templ);
493     gboolean ret = TRUE;
494     gint rc;
495 
496     g_debug("caching repo: %s (0x%s)", name, chksum);
497 
498     if (tmp_fd < 0) {
499         ret = FALSE;
500         g_set_error (error,
501                      DNF_ERROR,
502                      DNF_ERROR_FILE_INVALID,
503                      _("cannot create temporary file: %s"),
504                      tmp_fn_templ);
505         goto done;
506     } else {
507         FILE *fp = fdopen(tmp_fd, "w+");
508         if (!fp) {
509             ret = FALSE;
510             g_set_error (error,
511                         DNF_ERROR,
512                         DNF_ERROR_FILE_INVALID,
513                         _("failed opening tmp file: %s"),
514                         strerror(errno));
515             goto done;
516         }
517         rc = repo_write(repo, fp);
518         rc |= checksum_write(repoImpl->checksum, fp);
519         rc |= fclose(fp);
520         if (rc) {
521             ret = FALSE;
522             g_set_error (error,
523                         DNF_ERROR,
524                         DNF_ERROR_FILE_INVALID,
525                         _("write_main() failed writing data: %i"), rc);
526             goto done;
527         }
528     }
529     if (switchtosolv && repo_is_one_piece(repo)) {
530         /* switch over to written solv file activate paging */
531         FILE *fp = fopen(tmp_fn_templ, "r");
532         if (fp) {
533             repo_empty(repo, 1);
534             rc = repo_add_solv(repo, fp, 0);
535             fclose(fp);
536             if (rc) {
537                 /* this is pretty fatal */
538                 ret = FALSE;
539                 g_set_error_literal (error,
540                                      DNF_ERROR,
541                                      DNF_ERROR_FILE_INVALID,
542                                      _("write_main() failed to re-load "
543                                        "written solv file"));
544                 goto done;
545             }
546         }
547     }
548 
549     ret = mv(tmp_fn_templ, fn, error);
550     if (!ret)
551         goto done;
552     repoImpl->state_main = _HY_WRITTEN;
553 
554  done:
555     if (!ret && tmp_fd >= 0)
556         unlink(tmp_fn_templ);
557     g_free(tmp_fn_templ);
558     g_free(fn);
559     return ret;
560 }
561 
562 /* this filter makes sure only the updateinfo repodata is written */
563 static int
write_ext_updateinfo_filter(Repo * repo,Repokey * key,void * kfdata)564 write_ext_updateinfo_filter(Repo *repo, Repokey *key, void *kfdata)
565 {
566     auto data = static_cast<Repodata *>(kfdata);
567     if (key->name == 1 && (int) key->size != data->repodataid)
568         return -1;
569     return repo_write_stdkeyfilter(repo, key, 0);
570 }
571 
572 static int
write_ext_updateinfo(HyRepo hrepo,Repodata * data,FILE * fp)573 write_ext_updateinfo(HyRepo hrepo, Repodata *data, FILE *fp)
574 {
575     auto repoImpl = libdnf::repoGetImpl(hrepo);
576     Repo *repo = repoImpl->libsolvRepo;
577     int oldstart = repo->start;
578     repo->start = repoImpl->main_end;
579     repo->nsolvables -= repoImpl->main_nsolvables;
580     int res = repo_write_filtered(repo, fp, write_ext_updateinfo_filter, data, 0);
581     repo->start = oldstart;
582     repo->nsolvables += repoImpl->main_nsolvables;
583     return res;
584 }
585 
586 static gboolean
write_ext(DnfSack * sack,HyRepo hrepo,_hy_repo_repodata which_repodata,const char * suffix,GError ** error)587 write_ext(DnfSack *sack, HyRepo hrepo, _hy_repo_repodata which_repodata,
588           const char *suffix, GError **error)
589 {
590     auto repoImpl = libdnf::repoGetImpl(hrepo);
591     Repo *repo = repoImpl->libsolvRepo;
592     int ret = 0;
593     const char *name = repo->name;
594 
595     Id repodata = repo_get_repodata(hrepo, which_repodata);
596     assert(repodata);
597     Repodata *data = repo_id2repodata(repo, repodata);
598     char *fn = dnf_sack_give_cache_fn(sack, name, suffix);
599     char *tmp_fn_templ = solv_dupjoin(fn, ".XXXXXX", NULL);
600     int tmp_fd = mkstemp(tmp_fn_templ);
601     gboolean success;
602     if (tmp_fd < 0) {
603         success = FALSE;
604         g_set_error (error,
605                      DNF_ERROR,
606                      DNF_ERROR_FILE_INVALID,
607                      _("can not create temporary file %s"),
608                      tmp_fn_templ);
609         goto done;
610     } else {
611         FILE *fp = fdopen(tmp_fd, "w+");
612 
613         g_debug("%s: storing %s to: %s", __func__, repo->name, tmp_fn_templ);
614         if (which_repodata != _HY_REPODATA_UPDATEINFO)
615             ret |= repodata_write(data, fp);
616         else
617             ret |= write_ext_updateinfo(hrepo, data, fp);
618         ret |= checksum_write(repoImpl->checksum, fp);
619         ret |= fclose(fp);
620         if (ret) {
621             success = FALSE;
622             g_set_error (error,
623                         DNF_ERROR,
624                         DNF_ERROR_FAILED,
625                         _("write_ext(%1$d) has failed: %2$d"),
626                         which_repodata, ret);
627             goto done;
628         }
629     }
630 
631     if (repo_is_one_piece(repo) && which_repodata != _HY_REPODATA_UPDATEINFO) {
632         /* switch over to written solv file activate paging */
633         FILE *fp = fopen(tmp_fn_templ, "r");
634         if (fp) {
635             int flags = REPO_USE_LOADING | REPO_EXTEND_SOLVABLES;
636             /* do not pollute the main pool with directory component ids */
637             if (which_repodata == _HY_REPODATA_FILENAMES || which_repodata == _HY_REPODATA_OTHER)
638                 flags |= REPO_LOCALPOOL;
639             repodata_extend_block(data, repo->start, repo->end - repo->start);
640             data->state = REPODATA_LOADING;
641             repo_add_solv(repo, fp, flags);
642             data->state = REPODATA_AVAILABLE;
643             fclose(fp);
644         }
645     }
646 
647     if (!mv(tmp_fn_templ, fn, error)) {
648         success = FALSE;
649         goto done;
650     }
651     repo_update_state(hrepo, which_repodata, _HY_WRITTEN);
652     success = TRUE;
653  done:
654     if (ret && tmp_fd >=0 )
655         unlink(tmp_fn_templ);
656     g_free(tmp_fn_templ);
657     g_free(fn);
658     return success;
659 }
660 
661 static gboolean
load_yum_repo(DnfSack * sack,HyRepo hrepo,GError ** error)662 load_yum_repo(DnfSack *sack, HyRepo hrepo, GError **error)
663 {
664     auto repoImpl = libdnf::repoGetImpl(hrepo);
665     DnfSackPrivate *priv = GET_PRIVATE(sack);
666     gboolean retval = TRUE;
667     Pool *pool = priv->pool;
668     const char *name = hrepo->getId().c_str();
669     Repo *repo = repo_create(pool, name);
670     const char *fn_repomd = repoImpl->repomdFn.c_str();
671     char *fn_cache = dnf_sack_give_cache_fn(sack, name, NULL);
672 
673     FILE *fp_primary = NULL;
674     FILE *fp_repomd = NULL;
675     FILE *fp_cache = fopen(fn_cache, "r");
676     if (!fn_repomd) {
677         g_set_error (error,
678                      DNF_ERROR,
679                      DNF_ERROR_FILE_INVALID,
680                      _("null repo md file"));
681         retval = FALSE;
682         goto out;
683     }
684     fp_repomd = fopen(fn_repomd, "r");
685     if (fp_repomd == NULL) {
686         g_set_error (error,
687                      DNF_ERROR,
688                      DNF_ERROR_FILE_INVALID,
689                      _("can not read file %1$s: %2$s"),
690                      fn_repomd, strerror(errno));
691         retval = FALSE;
692         goto out;
693     }
694     checksum_fp(repoImpl->checksum, fp_repomd);
695 
696     if (can_use_repomd_cache(fp_cache, repoImpl->checksum)) {
697         const char *chksum = pool_checksum_str(pool, repoImpl->checksum);
698         g_debug("using cached %s (0x%s)", name, chksum);
699         if (repo_add_solv(repo, fp_cache, 0)) {
700             g_set_error (error,
701                          DNF_ERROR,
702                          DNF_ERROR_INTERNAL_ERROR,
703                          _("repo_add_solv() has failed."));
704             retval = FALSE;
705             goto out;
706         }
707         repoImpl->state_main = _HY_LOADED_CACHE;
708     } else {
709         auto primary = hrepo->getMetadataPath(MD_TYPE_PRIMARY);
710         if (primary.empty()) {
711             // It could happen when repomd file has no "primary" data or they are in unsupported
712             // format like zchunk
713             g_set_error (error,
714                          DNF_ERROR,
715                          DNF_ERROR_INTERNAL_ERROR,
716                          _("loading of MD_TYPE_PRIMARY has failed."));
717             retval = FALSE;
718             goto out;
719         }
720         fp_primary = solv_xfopen(primary.c_str(), "r");
721         assert(fp_primary);
722 
723         g_debug("fetching %s", name);
724         if (repo_add_repomdxml(repo, fp_repomd, 0) || \
725             repo_add_rpmmd(repo, fp_primary, 0, 0)) {
726             g_set_error (error,
727                          DNF_ERROR,
728                          DNF_ERROR_INTERNAL_ERROR,
729                          _("repo_add_repomdxml/rpmmd() has failed."));
730             retval = FALSE;
731             goto out;
732         }
733         repoImpl->state_main = _HY_LOADED_FETCH;
734     }
735 out:
736     if (fp_cache)
737         fclose(fp_cache);
738     if (fp_repomd)
739         fclose(fp_repomd);
740     if (fp_primary)
741         fclose(fp_primary);
742     g_free(fn_cache);
743 
744     if (retval) {
745         libdnf::repoGetImpl(hrepo)->attachLibsolvRepo(repo);
746         priv->provides_ready = 0;
747     } else
748         repo_free(repo, 1);
749     return retval;
750 }
751 
752 /**
753  * dnf_sack_set_cachedir:
754  * @sack: a #DnfSack instance.
755  * @value: a a filesystem path.
756  *
757  * Sets the location to store the metadata cache files.
758  *
759  * Since: 0.7.0
760  */
761 void
dnf_sack_set_cachedir(DnfSack * sack,const gchar * value)762 dnf_sack_set_cachedir (DnfSack *sack, const gchar *value)
763 {
764     DnfSackPrivate *priv = GET_PRIVATE(sack);
765     g_free (priv->cache_dir);
766     priv->cache_dir = g_strdup(value);
767 }
768 
769 /**
770  * dnf_sack_set_arch:
771  * @sack: a #DnfSack instance.
772  * @value: an architecture, e.g. "i386", or %NULL for autodetection.
773  * @error: a #GError or %NULL.
774  *
775  * Sets the system architecture to use for the sack. Calling this
776  * function is optional before a dnf_sack_setup() call.
777  *
778  * Returns: %TRUE for success
779  *
780  * Since: 0.7.0
781  */
782 gboolean
dnf_sack_set_arch(DnfSack * sack,const gchar * value,GError ** error)783 dnf_sack_set_arch (DnfSack *sack, const gchar *value, GError **error) try
784 {
785     DnfSackPrivate *priv = GET_PRIVATE(sack);
786     Pool *pool = dnf_sack_get_pool(sack);
787     const char *arch = value;
788     g_autofree gchar *detected = NULL;
789 
790     /* autodetect */
791     if (arch == NULL) {
792         if (hy_detect_arch(&detected)) {
793             g_set_error (error,
794                          DNF_ERROR,
795                          DNF_ERROR_INTERNAL_ERROR,
796                          _("failed to auto-detect architecture"));
797             return FALSE;
798         }
799         arch = detected;
800     }
801 
802     g_debug("Architecture is: %s", arch);
803     g_free (priv->arch);
804     priv->arch = g_strdup(arch);
805     pool_setdisttype(pool, DISTTYPE_RPM);
806     pool_setarch(pool, arch);
807 
808     /* Since one of commits after 0.6.20 libsolv allowes custom arches
809      * which means it will be 'newcoolarch' and 'noarch' always. */
810     priv->have_set_arch = TRUE;
811     return TRUE;
812 } CATCH_TO_GERROR(FALSE)
813 
814 /**
815  * dnf_sack_set_all_arch:
816  * @sack: a #DnfSack instance.
817  * @all_arch: new value for all_arch property.
818  *
819  * This is used for controlling whether an arch needs to
820  * be set within libsolv or not.
821  *
822  * Returns: Nothing.
823  *
824  * Since: 0.7.0
825  */
826 void
827 dnf_sack_set_all_arch (DnfSack *sack, gboolean all_arch)
828 {
829     DnfSackPrivate *priv = GET_PRIVATE(sack);
830     priv->all_arch = all_arch;
831 }
832 
833 /**
834  * dnf_sack_get_all_arch
835  * @sack: a #DnfSack instance.
836  *
837  * Returns: the state of all_arch.
838  *
839  * Since: 0.7.0
840  */
841 gboolean
dnf_sack_get_all_arch(DnfSack * sack)842 dnf_sack_get_all_arch (DnfSack *sack)
843 {
844     DnfSackPrivate *priv = GET_PRIVATE(sack);
845     return priv->all_arch;
846 }
847 
848 /*
849  * dnf_sack_set_allow_vendor_change:
850  * @sack: a #DnfSack instance.
851  * @allow_vendor_change is a boolean.
852  *
853  * Sets the value of allow vendor change to use for
854  * SOLVER_FLAG_ALLOW_VENDORCHANGE flag
855  *
856  * Returns: Nothing.
857  *
858  * Since: 0.54.3
859  *
860  * */
861 void
dnf_sack_set_allow_vendor_change(DnfSack * sack,gboolean allow_vendor_change)862 dnf_sack_set_allow_vendor_change(DnfSack *sack, gboolean allow_vendor_change)
863 {
864     DnfSackPrivate *priv = GET_PRIVATE(sack);
865     priv->allow_vendor_change = allow_vendor_change;
866 }
867 
868 /*
869  * dnf_sack_get_allow_vendor_change:
870  * @sack: a #DnfSack instance.
871  * @allow_vendor_change is a boolean.
872  *
873  * Gets the value of allow vendor change to use for
874  * SOLVER_FLAG_ALLOW_VENDORCHANGE flag
875  *
876  * Returns: True if flag set to 1, False if set to 0
877  *
878  * Since: 0.54.3
879  *
880  * */
881 gboolean
dnf_sack_get_allow_vendor_change(DnfSack * sack)882 dnf_sack_get_allow_vendor_change(DnfSack *sack)
883 {
884     DnfSackPrivate *priv = GET_PRIVATE(sack);
885     return priv->allow_vendor_change;
886 }
887 
888 /**
889  * dnf_sack_get_arch
890  * @sack: a #DnfSack instance.
891  *
892  * Returns: the state of all_arch.
893  *
894  * Since: 0.16.2
895  */
896 const char *
dnf_sack_get_arch(DnfSack * sack)897 dnf_sack_get_arch (DnfSack *sack)
898 {
899     DnfSackPrivate *priv = GET_PRIVATE(sack);
900     return priv->arch;
901 }
902 
903 /**
904  * dnf_sack_set_rootdir:
905  * @sack: a #DnfSack instance.
906  * @value: a directory path, or %NULL.
907  *
908  * Sets the install root location.
909  *
910  * Since: 0.7.0
911  */
912 void
dnf_sack_set_rootdir(DnfSack * sack,const gchar * value)913 dnf_sack_set_rootdir (DnfSack *sack, const gchar *value)
914 {
915     DnfSackPrivate *priv = GET_PRIVATE(sack);
916     pool_set_rootdir(priv->pool, value);
917     /* Don't look for running kernels if we're not operating live on
918      * the current system.
919      */
920     if (g_strcmp0(value, "/") != 0)
921         priv->running_kernel_fn = NULL;
922 }
923 
924 /**
925  * dnf_sack_setup:
926  * @sack: a #DnfSack instance.
927  * @flags: optional flags, e.g. %DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR.
928  * @error: a #GError or %NULL.
929  *
930  * Sets up a new package sack, the fundamental hawkey structure.
931  *
932  * Returns: %TRUE for success
933  *
934  * Since: 0.7.0
935  */
936 gboolean
dnf_sack_setup(DnfSack * sack,int flags,GError ** error)937 dnf_sack_setup(DnfSack *sack, int flags, GError **error) try
938 {
939     DnfSackPrivate *priv = GET_PRIVATE(sack);
940     Pool *pool = dnf_sack_get_pool(sack);
941 
942     /* we never called dnf_sack_set_cachedir() */
943     if (priv->cache_dir == NULL) {
944         if (geteuid() != 0) {
945             char *username = this_username();
946             char *path = pool_tmpjoin(pool, DEFAULT_CACHE_USER, "-", username);
947             path = pool_tmpappend(pool, path, "-", "XXXXXX");
948             priv->cache_dir = g_strdup(path);
949             g_free(username);
950         } else {
951             priv->cache_dir = g_strdup(DEFAULT_CACHE_ROOT);
952         }
953     }
954 
955     /* create the directory */
956     if (flags & DNF_SACK_SETUP_FLAG_MAKE_CACHE_DIR) {
957         if (mkcachedir(priv->cache_dir)) {
958             g_set_error (error,
959                          DNF_ERROR,
960                          DNF_ERROR_FILE_INVALID,
961                          _("failed creating cachedir %s"),
962                          priv->cache_dir);
963             return FALSE;
964         }
965     }
966 
967     /* never called dnf_sack_set_arch(), so autodetect */
968     if (!priv->have_set_arch && !priv->all_arch) {
969         if (!dnf_sack_set_arch (sack, NULL, error))
970             return FALSE;
971     }
972     return TRUE;
973 } CATCH_TO_GERROR(FALSE)
974 
975 /**
976  * dnf_sack_evr_cmp:
977  * @sack: a #DnfSack instance.
978  * @evr1: an EVR string.
979  * @evr2: another EVR string.
980  *
981  * Compares one EVR with another using the sack.
982  *
983  * Returns: 0 for equality
984  *
985  * Since: 0.7.0
986  */
987 int
988 dnf_sack_evr_cmp(DnfSack *sack, const char *evr1, const char *evr2)
989 {
990     g_autoptr(DnfSack) _sack = NULL;
991     if (!sack)
992         _sack = dnf_sack_new ();
993     else
994         _sack = static_cast<DnfSack *>(g_object_ref(sack));
995     return pool_evrcmp_str(dnf_sack_get_pool(_sack), evr1, evr2, EVRCMP_COMPARE);
996 }
997 
998 /**
999  * dnf_sack_get_cache_dir:
1000  * @sack: a #DnfSack instance.
1001  *
1002  * Gets the cache directory.
1003  *
1004  * Returns: The user-set cache-dir, or %NULL for not set
1005  *
1006  * Since: 0.7.0
1007  */
1008 const char *
dnf_sack_get_cache_dir(DnfSack * sack)1009 dnf_sack_get_cache_dir(DnfSack *sack)
1010 {
1011     DnfSackPrivate *priv = GET_PRIVATE(sack);
1012     return priv->cache_dir;
1013 }
1014 
1015 /**
1016  * dnf_sack_get_running_kernel:
1017  * @sack: a #DnfSack instance.
1018  *
1019  * Gets the running kernel.
1020  *
1021  * Returns: a #DnfPackage, or %NULL
1022  *
1023  * Since: 0.7.0
1024  */
1025 DnfPackage *
dnf_sack_get_running_kernel(DnfSack * sack)1026 dnf_sack_get_running_kernel(DnfSack *sack)
1027 {
1028     Id id = dnf_sack_running_kernel(sack);
1029     if (id < 0)
1030         return NULL;
1031     return dnf_package_new(sack, id);
1032 }
1033 
1034 /**
1035  * dnf_sack_give_cache_fn:
1036  * @sack: a #DnfSack instance.
1037  * @reponame: a repo name.
1038  * @ext: a file extension
1039  *
1040  * Gets a cache filename.
1041  *
1042  * Returns: a filename
1043  *
1044  * Since: 0.7.0
1045  */
1046 char *
dnf_sack_give_cache_fn(DnfSack * sack,const char * reponame,const char * ext)1047 dnf_sack_give_cache_fn(DnfSack *sack, const char *reponame, const char *ext)
1048 {
1049     DnfSackPrivate *priv = GET_PRIVATE(sack);
1050     assert(reponame);
1051     char *fn = solv_dupjoin(priv->cache_dir, "/", reponame);
1052     if (ext)
1053         return solv_dupappend(fn, ext, ".solvx");
1054     return solv_dupappend(fn, ".solv", NULL);
1055 }
1056 
1057 /**
1058  * dnf_sack_list_arches:
1059  * @sack: a #DnfSack instance.
1060  *
1061  * Creates list of architectures
1062  *
1063  * Returns: a list of architectures
1064  *
1065  * Since: 0.7.0
1066  */
1067 const char **
dnf_sack_list_arches(DnfSack * sack)1068 dnf_sack_list_arches(DnfSack *sack)
1069 {
1070     Pool *pool = dnf_sack_get_pool(sack);
1071     const int BLOCK_SIZE = 31;
1072     int c = 0;
1073     const char **ss = NULL;
1074 
1075     if (!(pool->id2arch && pool->lastarch))
1076         return NULL;
1077 
1078     for (Id id = 0; id <= pool->lastarch; ++id) {
1079         if (!pool->id2arch[id])
1080             continue;
1081         ss = static_cast<const char **>(solv_extend(ss, c, 1, sizeof(char*), BLOCK_SIZE));
1082         ss[c++] = pool_id2str(pool, id);
1083     }
1084     ss = static_cast<const char **>(solv_extend(ss, c, 1, sizeof(char*), BLOCK_SIZE));
1085     ss[c++] = NULL;
1086     return ss;
1087 }
1088 
1089 /**
1090  * dnf_sack_set_installonly:
1091  * @sack: a #DnfSack instance.
1092  * @installonly: an array of package names.
1093  *
1094  * Sets the packages to use for installonlyn.
1095  *
1096  * Since: 0.7.0
1097  */
1098 void
dnf_sack_set_installonly(DnfSack * sack,const char ** installonly)1099 dnf_sack_set_installonly(DnfSack *sack, const char **installonly)
1100 {
1101     DnfSackPrivate *priv = GET_PRIVATE(sack);
1102     const char *name;
1103 
1104     queue_empty(&priv->installonly);
1105     if (installonly == NULL)
1106         return;
1107     while ((name = *installonly++) != NULL)
1108         queue_pushunique(&priv->installonly, pool_str2id(priv->pool, name, 1));
1109 }
1110 
1111 /**
1112  * dnf_sack_get_installonly: (skip)
1113  * @sack: a #DnfSack instance.
1114  *
1115  * Gets the installonlyn packages.
1116  *
1117  * Returns: a Queue
1118  *
1119  * Since: 0.7.0
1120  */
1121 Queue *
dnf_sack_get_installonly(DnfSack * sack)1122 dnf_sack_get_installonly(DnfSack *sack)
1123 {
1124     DnfSackPrivate *priv = GET_PRIVATE(sack);
1125     return &priv->installonly;
1126 }
1127 
1128 /**
1129  * dnf_sack_set_installonly_limit:
1130  * @sack: a #DnfSack instance.
1131  * @limit: a the number of packages.
1132  *
1133  * Sets the installonly limit.
1134  *
1135  * Since: 0.7.0
1136  */
1137 void
dnf_sack_set_installonly_limit(DnfSack * sack,guint limit)1138 dnf_sack_set_installonly_limit(DnfSack *sack, guint limit)
1139 {
1140     DnfSackPrivate *priv = GET_PRIVATE(sack);
1141     priv->installonly_limit = limit;
1142 }
1143 
1144 /**
1145  * dnf_sack_get_installonly_limit:
1146  * @sack: a #DnfSack instance.
1147  *
1148  * Gets the installonly limit.
1149  *
1150  * Returns: integer value
1151  *
1152  * Since: 0.7.0
1153  */
1154 guint
dnf_sack_get_installonly_limit(DnfSack * sack)1155 dnf_sack_get_installonly_limit(DnfSack *sack)
1156 {
1157     DnfSackPrivate *priv = GET_PRIVATE(sack);
1158     return priv->installonly_limit;
1159 }
1160 
1161 static Repo *
dnf_sack_setup_cmdline_repo(DnfSack * sack)1162 dnf_sack_setup_cmdline_repo(DnfSack *sack)
1163 {
1164     DnfSackPrivate *priv = GET_PRIVATE(sack);
1165     if (!priv->cmdline_repo) {
1166          HyRepo hrepo = hy_repo_create(HY_CMDLINE_REPO_NAME);
1167          auto repoImpl = libdnf::repoGetImpl(hrepo);
1168          Repo *repo = repo_create(dnf_sack_get_pool(sack), HY_CMDLINE_REPO_NAME);
1169          repo->appdata = hrepo;
1170          repoImpl->libsolvRepo = repo;
1171          repoImpl->needs_internalizing = 1;
1172          priv->cmdline_repo = repo;
1173     }
1174     return priv->cmdline_repo;
1175 }
1176 
1177 DnfPackage *
dnf_sack_add_cmdline_package_flags(DnfSack * sack,const char * fn,const int flags)1178 dnf_sack_add_cmdline_package_flags(DnfSack *sack, const char *fn, const int flags)
1179 {
1180     if (!is_readable_rpm(fn)) {
1181         g_warning("not a readable RPM file: %s, skipping", fn);
1182         return NULL;
1183     }
1184     DnfSackPrivate *priv = GET_PRIVATE(sack);
1185     Repo *repo = dnf_sack_setup_cmdline_repo(sack);
1186     Id p;
1187     priv->provides_ready = 0;    /* triggers internalizing later */
1188     p = repo_add_rpm(repo, fn, flags);
1189     if (p == 0) {
1190         g_warning ("failed to read RPM: %s, skipping",
1191                    pool_errstr (dnf_sack_get_pool (sack)));
1192         return NULL;
1193     }
1194     auto hrepo = static_cast<HyRepo>(repo->appdata);
1195     libdnf::repoGetImpl(hrepo)->needs_internalizing = 1;
1196     priv->considered_uptodate = FALSE;   /* triggers recompute_considered later */
1197     return dnf_package_new(sack, p);
1198 }
1199 
1200 /**
1201  * dnf_sack_add_cmdline_package:
1202  * @sack: a #DnfSack instance.
1203  * @fn: a filename.
1204  *
1205  * Adds the given .rpm file to the command line repo.
1206  *
1207  * Returns: a #DnfPackage, or %NULL
1208  *
1209  * Since: 0.7.0
1210  */
1211 DnfPackage *
dnf_sack_add_cmdline_package(DnfSack * sack,const char * fn)1212 dnf_sack_add_cmdline_package(DnfSack *sack, const char *fn)
1213 {
1214     return dnf_sack_add_cmdline_package_flags(sack, fn,
1215                                REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|
1216                                RPM_ADD_WITH_HDRID|RPM_ADD_WITH_SHA256SUM);
1217 }
1218 
1219 DnfPackage *
dnf_sack_add_cmdline_package_nochecksum(DnfSack * sack,const char * fn)1220 dnf_sack_add_cmdline_package_nochecksum(DnfSack *sack, const char *fn)
1221 {
1222     return dnf_sack_add_cmdline_package_flags(sack, fn,
1223                                REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE);
1224 }
1225 
1226 /**
1227  * dnf_sack_count:
1228  * @sack: a #DnfSack instance.
1229  *
1230  * Gets the number of items in the sack.
1231  *
1232  * Returns: number of solvables.
1233  *
1234  * Since: 0.7.0
1235  */
1236 int
dnf_sack_count(DnfSack * sack)1237 dnf_sack_count(DnfSack *sack)
1238 {
1239     int cnt = 0;
1240     Id p;
1241     Pool *pool = dnf_sack_get_pool(sack);
1242 
1243     FOR_PKG_SOLVABLES(p)
1244         cnt++;
1245     return cnt;
1246 }
1247 
1248 static void
dnf_sack_add_excludes_or_includes(DnfSack * sack,Map ** dest,const DnfPackageSet * pkgset)1249 dnf_sack_add_excludes_or_includes(DnfSack *sack, Map **dest, const DnfPackageSet *pkgset)
1250 {
1251     Map *destmap = *dest;
1252     if (destmap == NULL) {
1253         destmap = static_cast<Map *>(g_malloc0(sizeof(Map)));
1254         Pool *pool = dnf_sack_get_pool(sack);
1255         map_init(destmap, pool->nsolvables);
1256         *dest = destmap;
1257     }
1258 
1259     auto pkgmap = pkgset->getMap();
1260     map_or(destmap, pkgmap);
1261     DnfSackPrivate *priv = GET_PRIVATE(sack);
1262     priv->considered_uptodate = FALSE;
1263 }
1264 
1265 /**
1266  * dnf_sack_add_excludes:
1267  * @sack: a #DnfSack instance.
1268  * @pset: a #DnfPackageSet or %NULL.
1269  *
1270  * Adds excludes to the sack.
1271  *
1272  * Since: 0.7.0
1273  */
1274 void
dnf_sack_add_excludes(DnfSack * sack,const DnfPackageSet * pset)1275 dnf_sack_add_excludes(DnfSack *sack, const DnfPackageSet *pset)
1276 {
1277     DnfSackPrivate *priv = GET_PRIVATE(sack);
1278     dnf_sack_add_excludes_or_includes(sack, &priv->pkg_excludes, pset);
1279 }
1280 
1281 /**
1282  * dnf_sack_add_module_excludes:
1283  * @sack: a #DnfSack instance.
1284  * @pset: a #DnfPackageSet or %NULL.
1285  *
1286  * Adds excludes to the sack.
1287  *
1288  * Since: 0.13.4
1289  */
1290 void
dnf_sack_add_module_excludes(DnfSack * sack,const DnfPackageSet * pset)1291 dnf_sack_add_module_excludes(DnfSack *sack, const DnfPackageSet *pset)
1292 {
1293     DnfSackPrivate *priv = GET_PRIVATE(sack);
1294     dnf_sack_add_excludes_or_includes(sack, &priv->module_excludes, pset);
1295 }
1296 
1297 /**
1298  * dnf_sack_add_includes:
1299  * @sack: a #DnfSack instance.
1300  * @pset: a #DnfPackageSet or %NULL.
1301  *
1302  * Add includes to the sack.
1303  *
1304  * Since: 0.7.0
1305  */
1306 void
dnf_sack_add_includes(DnfSack * sack,const DnfPackageSet * pset)1307 dnf_sack_add_includes(DnfSack *sack, const DnfPackageSet *pset)
1308 {
1309     DnfSackPrivate *priv = GET_PRIVATE(sack);
1310     dnf_sack_add_excludes_or_includes(sack, &priv->pkg_includes, pset);
1311 }
1312 
1313 static void
dnf_sack_remove_excludes_or_includes(DnfSack * sack,Map * from,const DnfPackageSet * pkgset)1314 dnf_sack_remove_excludes_or_includes(DnfSack *sack, Map *from, const DnfPackageSet *pkgset)
1315 {
1316     if (from == NULL)
1317         return;
1318     auto pkgmap = pkgset->getMap();
1319     map_subtract(from, pkgmap);
1320     DnfSackPrivate *priv = GET_PRIVATE(sack);
1321     priv->considered_uptodate = FALSE;
1322 }
1323 
1324 /**
1325  * dnf_sack_remove_excludes:
1326  * @sack: a #DnfSack instance.
1327  * @pset: a #DnfPackageSet or %NULL.
1328  *
1329  * Removes excludes from the sack.
1330  *
1331  * Since: 0.9.4
1332  */
1333 void
dnf_sack_remove_excludes(DnfSack * sack,const DnfPackageSet * pset)1334 dnf_sack_remove_excludes(DnfSack *sack, const DnfPackageSet *pset)
1335 {
1336     DnfSackPrivate *priv = GET_PRIVATE(sack);
1337     dnf_sack_remove_excludes_or_includes(sack, priv->pkg_excludes, pset);
1338 }
1339 
1340 /**
1341  * dnf_sack_remove_module_excludes:
1342  * @sack: a #DnfSack instance.
1343  * @pset: a #DnfPackageSet or %NULL.
1344  *
1345  * Removes excludes from the sack.
1346  *
1347  * Since: 0.13.4
1348  */
1349 void
dnf_sack_remove_module_excludes(DnfSack * sack,const DnfPackageSet * pset)1350 dnf_sack_remove_module_excludes(DnfSack *sack, const DnfPackageSet *pset)
1351 {
1352     DnfSackPrivate *priv = GET_PRIVATE(sack);
1353     dnf_sack_remove_excludes_or_includes(sack, priv->module_excludes, pset);
1354 }
1355 
1356 /**
1357  * dnf_sack_remove_includes:
1358  * @sack: a #DnfSack instance.
1359  * @pset: a #DnfPackageSet or %NULL.
1360  *
1361  * Removes includes from the sack.
1362  *
1363  * Since: 0.9.4
1364  */
1365 void
dnf_sack_remove_includes(DnfSack * sack,const DnfPackageSet * pset)1366 dnf_sack_remove_includes(DnfSack *sack, const DnfPackageSet *pset)
1367 {
1368     DnfSackPrivate *priv = GET_PRIVATE(sack);
1369     dnf_sack_remove_excludes_or_includes(sack, priv->pkg_includes, pset);
1370 }
1371 
1372 static void
dnf_sack_set_excludes_or_includes(DnfSack * sack,Map ** dest,const DnfPackageSet * pkgset)1373 dnf_sack_set_excludes_or_includes(DnfSack *sack, Map **dest, const DnfPackageSet *pkgset)
1374 {
1375     if (*dest == NULL && pkgset == NULL)
1376         return;
1377 
1378     *dest = free_map_fully(*dest);
1379     if (pkgset) {
1380         *dest = static_cast<Map *>(g_malloc0(sizeof(Map)));
1381         auto pkgmap = pkgset->getMap();
1382         map_init_clone(*dest, pkgmap);
1383     }
1384     DnfSackPrivate *priv = GET_PRIVATE(sack);
1385     priv->considered_uptodate = FALSE;
1386 }
1387 
1388 void
dnf_sack_set_module_includes(DnfSack * sack,const DnfPackageSet * pset)1389 dnf_sack_set_module_includes(DnfSack *sack, const DnfPackageSet *pset)
1390 {
1391     if (!pset) {
1392         return;
1393     }
1394     DnfSackPrivate *priv = GET_PRIVATE(sack);
1395     free_map_fully(priv->module_includes);
1396     priv->module_includes = static_cast<Map *>(g_malloc0(sizeof(Map)));
1397     auto pkgmap = pset->getMap();
1398     map_init_clone(priv->module_includes, pkgmap);
1399 }
1400 
1401 /**
1402  * dnf_sack_set_excludes:
1403  * @sack: a #DnfSack instance.
1404  * @pset: a #DnfPackageSet or %NULL.
1405  *
1406  * Set excludes for the sack.
1407  *
1408  * Since: 0.7.0
1409  */
1410 void
dnf_sack_set_excludes(DnfSack * sack,const DnfPackageSet * pset)1411 dnf_sack_set_excludes(DnfSack *sack, const DnfPackageSet *pset)
1412 {
1413     DnfSackPrivate *priv = GET_PRIVATE(sack);
1414     dnf_sack_set_excludes_or_includes(sack, &priv->pkg_excludes, pset);
1415 }
1416 
1417 /**
1418  * dnf_sack_set_module_excludes:
1419  * @sack: a #DnfSack instance.
1420  * @pset: a #DnfPackageSet or %NULL.
1421  *
1422  * Set excludes for the sack.
1423  *
1424  * Since: 0.13.4
1425  */
1426 void
dnf_sack_set_module_excludes(DnfSack * sack,const DnfPackageSet * pset)1427 dnf_sack_set_module_excludes(DnfSack *sack, const DnfPackageSet *pset)
1428 {
1429     DnfSackPrivate *priv = GET_PRIVATE(sack);
1430     dnf_sack_set_excludes_or_includes(sack, &priv->module_excludes, pset);
1431 }
1432 
1433 /**
1434  * dnf_sack_set_includes:
1435  * @sack: a #DnfSack instance.
1436  * @pset: a #DnfPackageSet or %NULL.
1437  *
1438  * Set any sack includes.
1439  *
1440  * Since: 0.7.0
1441  */
1442 void
dnf_sack_set_includes(DnfSack * sack,const DnfPackageSet * pset)1443 dnf_sack_set_includes(DnfSack *sack, const DnfPackageSet *pset)
1444 {
1445     DnfSackPrivate *priv = GET_PRIVATE(sack);
1446     dnf_sack_set_excludes_or_includes(sack, &priv->pkg_includes, pset);
1447 }
1448 
1449 /**
1450  * dnf_sack_reset_excludes:
1451  * @sack: a #DnfSack instance.
1452  *
1453  * Reset excludes (remove excludes map from memory).
1454  *
1455  * Since: 0.9.4
1456  */
1457 void
dnf_sack_reset_excludes(DnfSack * sack)1458 dnf_sack_reset_excludes(DnfSack *sack)
1459 {
1460     dnf_sack_set_excludes(sack, NULL);
1461 }
1462 
1463 /**
1464  * dnf_sack_reset_module_excludes:
1465  * @sack: a #DnfSack instance.
1466  *
1467  * Reset excludes (remove excludes map from memory).
1468  *
1469  * Since: 0.13.4
1470  */
1471 void
dnf_sack_reset_module_excludes(DnfSack * sack)1472 dnf_sack_reset_module_excludes(DnfSack *sack)
1473 {
1474     dnf_sack_set_module_excludes(sack, NULL);
1475 }
1476 
1477 /**
1478  * dnf_sack_reset_includes:
1479  * @sack: a #DnfSack instance.
1480  *
1481  * Reset includes (remove includes map from memory).
1482  *
1483  * Since: 0.9.4
1484  */
1485 void
dnf_sack_reset_includes(DnfSack * sack)1486 dnf_sack_reset_includes(DnfSack *sack)
1487 {
1488     dnf_sack_set_includes(sack, NULL);
1489 }
1490 
1491 /**
1492  * dnf_sack_get_excludes:
1493  * @sack: a #DnfSack instance.
1494  * @pset: a #DnfPackageSet or %NULL.
1495  *
1496  * Gets sack excludes.
1497  *
1498  * Since: 0.9.4
1499  */
1500 DnfPackageSet *
dnf_sack_get_excludes(DnfSack * sack)1501 dnf_sack_get_excludes(DnfSack *sack)
1502 {
1503     DnfSackPrivate *priv = GET_PRIVATE(sack);
1504     Map *excl = priv->pkg_excludes;
1505     return excl ? dnf_packageset_from_bitmap(sack, excl) : NULL;
1506 }
1507 
1508 /**
1509  * dnf_sack_get_module_excludes:
1510  * @sack: a #DnfSack instance.
1511  * @pset: a #DnfPackageSet or %NULL.
1512  *
1513  * Gets sack excludes.
1514  *
1515  * Since: 0.13.4
1516  */
1517 DnfPackageSet *
dnf_sack_get_module_excludes(DnfSack * sack)1518 dnf_sack_get_module_excludes(DnfSack *sack)
1519 {
1520     DnfSackPrivate *priv = GET_PRIVATE(sack);
1521     Map *excl = priv->module_excludes;
1522     return excl ? dnf_packageset_from_bitmap(sack, excl) : NULL;
1523 }
1524 
1525 /**
1526  * dnf_sack_get_module_includes:
1527  * @sack: a #DnfSack instance.
1528  * @pset: a #DnfPackageSet or %NULL.
1529  *
1530  * Since: 0.16.1
1531  */
1532 DnfPackageSet *
dnf_sack_get_module_includes(DnfSack * sack)1533 dnf_sack_get_module_includes(DnfSack *sack)
1534 {
1535     DnfSackPrivate *priv = GET_PRIVATE(sack);
1536     Map *excl = priv->module_includes;
1537     return excl ? dnf_packageset_from_bitmap(sack, excl) : NULL;
1538 }
1539 
1540 /**
1541  * dnf_sack_get_includes:
1542  * @sack: a #DnfSack instance.
1543  *
1544  * Gets sack includes.
1545  *
1546  * Since: 0.9.4
1547  */
1548 DnfPackageSet *
dnf_sack_get_includes(DnfSack * sack)1549 dnf_sack_get_includes(DnfSack *sack)
1550 {
1551     DnfSackPrivate *priv = GET_PRIVATE(sack);
1552     Map *incl = priv->pkg_includes;
1553     return incl ? dnf_packageset_from_bitmap(sack, incl) : NULL;
1554 }
1555 
1556 /**
1557  * dnf_sack_set_use_includes:
1558  * @sack: a #DnfSack instance.
1559  * @repo_name: a name of repo or %NULL for all repos.
1560  * @enabled: a use includes for a repo or all repos.
1561  *
1562  * Enable/disable usage of includes for repo/all-repos.
1563  *
1564  * Returns: FALSE if error occurred (unknown reponame) else TRUE.
1565  *
1566  * Since: 0.9.4
1567  */
1568 gboolean
dnf_sack_set_use_includes(DnfSack * sack,const char * reponame,gboolean enabled)1569 dnf_sack_set_use_includes(DnfSack *sack, const char *reponame, gboolean enabled)
1570 {
1571     DnfSackPrivate *priv = GET_PRIVATE(sack);
1572     Pool *pool = dnf_sack_get_pool(sack);
1573 
1574     if (reponame) {
1575         HyRepo hyrepo = hrepo_by_name(sack, reponame);
1576         if (!hyrepo)
1577             return FALSE;
1578         if (hyrepo->getUseIncludes() != enabled)
1579         {
1580             hyrepo->setUseIncludes(enabled);
1581             priv->considered_uptodate = FALSE;
1582         }
1583     } else {
1584         Id repoid;
1585         Repo *repo;
1586         FOR_REPOS(repoid, repo) {
1587             auto hyrepo = static_cast<HyRepo>(pool->repos[repoid]->appdata);
1588             if (hyrepo->getUseIncludes() != enabled)
1589             {
1590                 hyrepo->setUseIncludes(enabled);
1591                 priv->considered_uptodate = FALSE;
1592             }
1593         }
1594     }
1595     return TRUE;
1596 }
1597 
1598 /**
1599  * dnf_sack_set_provides_not_ready:
1600  * @sack: a #DnfSack instance.
1601  *
1602  * Mark sack to recompute provides
1603  *
1604  * Since: 0.16.3
1605  */
1606 void
dnf_sack_set_provides_not_ready(DnfSack * sack)1607 dnf_sack_set_provides_not_ready(DnfSack *sack)
1608 {
1609     DnfSackPrivate *priv = GET_PRIVATE(sack);
1610     priv->provides_ready = FALSE;
1611 }
1612 
1613 /**
1614  * dnf_sack_set_considered_to_update:
1615  * @sack: a #DnfSack instance.
1616  *
1617  * Mark sack to recompute considered
1618  *
1619  * Since: 0.16.3
1620  */
1621 void
dnf_sack_set_considered_to_update(DnfSack * sack)1622 dnf_sack_set_considered_to_update(DnfSack *sack)
1623 {
1624     DnfSackPrivate *priv = GET_PRIVATE(sack);
1625     priv->considered_uptodate = FALSE;
1626 }
1627 
1628 /**
1629  * dnf_sack_get_use_includes:
1630  * @sack: a #DnfSack instance.
1631  * @repo_name: a name of repo or %NULL for all repos.
1632  * @enabled: a returned state of includes for repo
1633  *
1634  * Enable/disable usage of includes for repo/all-repos.
1635  *
1636  * Returns: FALSE if error occurred (unknown reponame) else TRUE.
1637  *
1638  * Since: 0.9.4
1639  */
1640 gboolean
dnf_sack_get_use_includes(DnfSack * sack,const char * reponame,gboolean * enabled)1641 dnf_sack_get_use_includes(DnfSack *sack, const char *reponame, gboolean *enabled)
1642 {
1643     assert(reponame);
1644     HyRepo hyrepo = hrepo_by_name(sack, reponame);
1645     if (!hyrepo)
1646         return FALSE;
1647     *enabled = hyrepo->getUseIncludes();
1648     return TRUE;
1649 }
1650 
1651 /**
1652  * dnf_sack_repo_enabled:
1653  * @sack: a #DnfSack instance.
1654  * @reponame: a repo name.
1655  * @enabled: the enabled state.
1656  *
1657  * Enable repository
1658  *
1659  * Returns: %TRUE for success
1660  *
1661  * Since: 0.7.0
1662  */
1663 int
dnf_sack_repo_enabled(DnfSack * sack,const char * reponame,int enabled)1664 dnf_sack_repo_enabled(DnfSack *sack, const char *reponame, int enabled)
1665 {
1666     DnfSackPrivate *priv = GET_PRIVATE(sack);
1667     Pool *pool = dnf_sack_get_pool(sack);
1668     Repo *repo = repo_by_name(sack, reponame);
1669     Map *excl = priv->repo_excludes;
1670 
1671     if (repo == NULL)
1672         return DNF_ERROR_INTERNAL_ERROR;
1673     if (excl == NULL) {
1674         excl = static_cast<Map *>(g_malloc0(sizeof(Map)));
1675         map_init(excl, pool->nsolvables);
1676         priv->repo_excludes = excl;
1677     }
1678     repo->disabled = !enabled;
1679     priv->provides_ready = 0;
1680 
1681     Id p;
1682     Solvable *s;
1683     if (repo->disabled)
1684         FOR_REPO_SOLVABLES(repo, p, s)
1685             MAPSET(priv->repo_excludes, p);
1686     else
1687         FOR_REPO_SOLVABLES(repo, p, s)
1688             MAPCLR(priv->repo_excludes, p);
1689     priv->considered_uptodate = FALSE;
1690     return 0;
1691 }
1692 
1693 /**
1694  * dnf_sack_load_system_repo:
1695  * @sack: a #DnfSack instance.
1696  * @a_hrepo: a rpmdb repo.
1697  * @flags: what to load into the sack, e.g. %DNF_SACK_LOAD_FLAG_USE_FILELISTS.
1698  * @error: a #GError or %NULL.
1699  *
1700  * Loads the rpmdb into the sack.
1701  *
1702  * Returns: %TRUE for success
1703  *
1704  * Since: 0.7.0
1705  */
1706 gboolean
dnf_sack_load_system_repo(DnfSack * sack,HyRepo a_hrepo,int flags,GError ** error)1707 dnf_sack_load_system_repo(DnfSack *sack, HyRepo a_hrepo, int flags, GError **error) try
1708 {
1709     DnfSackPrivate *priv = GET_PRIVATE(sack);
1710     Pool *pool = dnf_sack_get_pool(sack);
1711     gboolean ret = TRUE;
1712     HyRepo hrepo = a_hrepo;
1713     Repo *repo;
1714 
1715     if (hrepo) {
1716         auto repoImpl = libdnf::repoGetImpl(hrepo);
1717         repoImpl->id = HY_SYSTEM_REPO_NAME;
1718         repoImpl->conf->name().set(libdnf::Option::Priority::RUNTIME, HY_SYSTEM_REPO_NAME);
1719     } else
1720         hrepo = hy_repo_create(HY_SYSTEM_REPO_NAME);
1721     auto repoImpl = libdnf::repoGetImpl(hrepo);
1722 
1723     repoImpl->load_flags = flags &= ~DNF_SACK_LOAD_FLAG_BUILD_CACHE;
1724 
1725     repo = repo_create(pool, HY_SYSTEM_REPO_NAME);
1726 
1727     g_debug("fetching rpmdb");
1728     int flagsrpm = REPO_REUSE_REPODATA | RPM_ADD_WITH_HDRID | REPO_USE_ROOTDIR;
1729     int rc = repo_add_rpmdb_reffp(repo, NULL, flagsrpm);
1730     if (!rc) {
1731         repoImpl->state_main = _HY_LOADED_FETCH;
1732     } else {
1733         repo_free(repo, 1);
1734         ret = FALSE;
1735         g_set_error (error,
1736                      DNF_ERROR,
1737                      DNF_ERROR_FILE_INVALID,
1738                      _("failed loading RPMDB"));
1739         goto finish;
1740     }
1741 
1742     libdnf::repoGetImpl(hrepo)->attachLibsolvRepo(repo);
1743     pool_set_installed(pool, repo);
1744     priv->provides_ready = 0;
1745 
1746     repoImpl->main_nsolvables = repo->nsolvables;
1747     repoImpl->main_nrepodata = repo->nrepodata;
1748     repoImpl->main_end = repo->end;
1749     priv->considered_uptodate = FALSE;
1750 
1751  finish:
1752     if (a_hrepo == NULL)
1753         hy_repo_free(hrepo);
1754     return ret;
1755 } CATCH_TO_GERROR(FALSE)
1756 
1757 /**
1758  * dnf_sack_load_repo:
1759  * @sack: a #DnfSack instance.
1760  * @repo: a #HyRepo.
1761  * @flags: what to load into the sack, e.g. %DNF_SACK_LOAD_FLAG_USE_FILELISTS.
1762  * @error: a #GError, or %NULL.
1763  *
1764  * Loads a remote repo into the sack.
1765  *
1766  * Returns: %TRUE for success
1767  *
1768  * Since: 0.7.0
1769  */
1770 gboolean
1771 dnf_sack_load_repo(DnfSack *sack, HyRepo repo, int flags, GError **error) try
1772 {
1773     DnfSackPrivate *priv = GET_PRIVATE(sack);
1774     auto repoImpl = libdnf::repoGetImpl(repo);
1775     GError *error_local = NULL;
1776     const int build_cache = flags & DNF_SACK_LOAD_FLAG_BUILD_CACHE;
1777     gboolean retval;
1778     if (!load_yum_repo(sack, repo, error))
1779         return FALSE;
1780     repoImpl->load_flags = flags;
1781     if (repoImpl->state_main == _HY_LOADED_FETCH && build_cache) {
1782         if (!write_main(sack, repo, 1, error))
1783             return FALSE;
1784     }
1785     repoImpl->main_nsolvables = repoImpl->libsolvRepo->nsolvables;
1786     repoImpl->main_nrepodata = repoImpl->libsolvRepo->nrepodata;
1787     repoImpl->main_end = repoImpl->libsolvRepo->end;
1788     if (flags & DNF_SACK_LOAD_FLAG_USE_FILELISTS) {
1789         retval = load_ext(sack, repo, _HY_REPODATA_FILENAMES,
1790                           HY_EXT_FILENAMES, MD_TYPE_FILELISTS,
1791                           load_filelists_cb, &error_local);
1792         /* allow missing files */
1793         if (!retval) {
1794             if (g_error_matches (error_local,
1795                                  DNF_ERROR,
1796                                  DNF_ERROR_NO_CAPABILITY)) {
1797                 g_debug("no filelists metadata available for %s", repoImpl->conf->name().getValue().c_str());
1798                 g_clear_error (&error_local);
1799             } else {
1800                 g_propagate_error (error, error_local);
1801                 return FALSE;
1802             }
1803         }
1804         if (repoImpl->state_filelists == _HY_LOADED_FETCH && build_cache) {
1805             if (!write_ext(sack, repo,
1806                            _HY_REPODATA_FILENAMES,
1807                            HY_EXT_FILENAMES, error))
1808                 return FALSE;
1809         }
1810     }
1811     if (flags & DNF_SACK_LOAD_FLAG_USE_OTHER) {
1812         retval = load_ext(sack, repo, _HY_REPODATA_OTHER,
1813                           HY_EXT_OTHER, MD_TYPE_OTHER,
1814                           load_other_cb, &error_local);
1815         /* allow missing files */
1816         if (!retval) {
1817             if (g_error_matches (error_local,
1818                                  DNF_ERROR,
1819                                  DNF_ERROR_NO_CAPABILITY)) {
1820                 g_debug("no other metadata available for %s", repoImpl->conf->name().getValue().c_str());
1821                 g_clear_error (&error_local);
1822             } else {
1823                 g_propagate_error (error, error_local);
1824                 return FALSE;
1825             }
1826         }
1827         if (repoImpl->state_other == _HY_LOADED_FETCH && build_cache) {
1828             if (!write_ext(sack, repo,
1829                            _HY_REPODATA_OTHER,
1830                            HY_EXT_OTHER, error))
1831                 return FALSE;
1832         }
1833     }
1834     if (flags & DNF_SACK_LOAD_FLAG_USE_PRESTO) {
1835         retval = load_ext(sack, repo, _HY_REPODATA_PRESTO,
1836                           HY_EXT_PRESTO, MD_TYPE_PRESTODELTA,
1837                           load_presto_cb, &error_local);
1838         if (!retval) {
1839             if (g_error_matches (error_local,
1840                                  DNF_ERROR,
1841                                  DNF_ERROR_NO_CAPABILITY)) {
1842                 g_debug("no presto metadata available for %s", repoImpl->conf->name().getValue().c_str());
1843                 g_clear_error (&error_local);
1844             } else {
1845                 g_propagate_error (error, error_local);
1846                 return FALSE;
1847             }
1848         }
1849         if (repoImpl->state_presto == _HY_LOADED_FETCH && build_cache)
1850             if (!write_ext(sack, repo, _HY_REPODATA_PRESTO, HY_EXT_PRESTO, error))
1851                 return FALSE;
1852     }
1853     /* updateinfo must come *after* all other extensions, as it is not a real
1854        extension, but contains a new set of packages */
1855     if (flags & DNF_SACK_LOAD_FLAG_USE_UPDATEINFO) {
1856         retval = load_ext(sack, repo, _HY_REPODATA_UPDATEINFO,
1857                           HY_EXT_UPDATEINFO, MD_TYPE_UPDATEINFO,
1858                           load_updateinfo_cb, &error_local);
1859         /* allow missing files */
1860         if (!retval) {
1861             if (g_error_matches (error_local,
1862                                  DNF_ERROR,
1863                                  DNF_ERROR_NO_CAPABILITY)) {
1864                 g_debug("no updateinfo available for %s", repoImpl->conf->name().getValue().c_str());
1865                 g_clear_error (&error_local);
1866             } else {
1867                 g_propagate_error (error, error_local);
1868                 return FALSE;
1869             }
1870         }
1871         if (repoImpl->state_updateinfo == _HY_LOADED_FETCH && build_cache)
1872             if (!write_ext(sack, repo, _HY_REPODATA_UPDATEINFO, HY_EXT_UPDATEINFO, error))
1873                 return FALSE;
1874     }
1875     priv->considered_uptodate = FALSE;
1876     return TRUE;
CATCH_TO_GERROR(FALSE)1877 } CATCH_TO_GERROR(FALSE)
1878 
1879 // internal to hawkey
1880 
1881 // return true if q1 is a superset of q2
1882 // only works if there are no duplicates both in q1 and q2
1883 // the map parameter must point to an empty map that can hold all ids
1884 // (it is also returned empty)
1885 static int
1886 is_superset(Queue *q1, Queue *q2, Map *m)
1887 {
1888     int i, cnt = 0;
1889     for (i = 0; i < q2->count; i++)
1890         MAPSET(m, q2->elements[i]);
1891     for (i = 0; i < q1->count; i++)
1892         if (MAPTST(m, q1->elements[i]))
1893             cnt++;
1894     for (i = 0; i < q2->count; i++)
1895         MAPCLR(m, q2->elements[i]);
1896     return cnt == q2->count;
1897 }
1898 
1899 
1900 static void
rewrite_repos(DnfSack * sack,Queue * addedfileprovides,Queue * addedfileprovides_inst)1901 rewrite_repos(DnfSack *sack, Queue *addedfileprovides,
1902               Queue *addedfileprovides_inst)
1903 {
1904     Pool *pool = dnf_sack_get_pool(sack);
1905     int i;
1906 
1907     Map providedids;
1908     map_init(&providedids, pool->ss.nstrings);
1909 
1910     Queue fileprovidesq;
1911     queue_init(&fileprovidesq);
1912 
1913     Repo *repo;
1914     FOR_REPOS(i, repo) {
1915         auto hrepo = static_cast<HyRepo>(repo->appdata);
1916         if (!hrepo)
1917             continue;
1918         auto repoImpl = libdnf::repoGetImpl(hrepo);
1919         if (!(repoImpl->load_flags & DNF_SACK_LOAD_FLAG_BUILD_CACHE))
1920             continue;
1921         if (repoImpl->main_nrepodata < 2)
1922             continue;
1923         /* now check if the repo already contains all of our file provides */
1924         Queue *addedq = repo == pool->installed && addedfileprovides_inst ?
1925             addedfileprovides_inst : addedfileprovides;
1926         if (!addedq->count)
1927             continue;
1928         Repodata *data = repo_id2repodata(repo, 1);
1929         queue_empty(&fileprovidesq);
1930         if (repodata_lookup_idarray(data, SOLVID_META,
1931                                     REPOSITORY_ADDEDFILEPROVIDES,
1932                                     &fileprovidesq)) {
1933             if (is_superset(&fileprovidesq, addedq, &providedids))
1934                 continue;
1935         }
1936         repodata_set_idarray(data, SOLVID_META,
1937                              REPOSITORY_ADDEDFILEPROVIDES, addedq);
1938         repodata_internalize(data);
1939         /* re-write main data only */
1940         int oldnrepodata = repo->nrepodata;
1941         int oldnsolvables = repo->nsolvables;
1942         int oldend = repo->end;
1943         repo->nrepodata = repoImpl->main_nrepodata;
1944         repo->nsolvables = repoImpl->main_nsolvables;
1945         repo->end = repoImpl->main_end;
1946         g_debug("rewriting repo: %s", repo->name);
1947         write_main(sack, hrepo, 0, NULL);
1948         repo->nrepodata = oldnrepodata;
1949         repo->nsolvables = oldnsolvables;
1950         repo->end = oldend;
1951     }
1952     queue_free(&fileprovidesq);
1953     map_free(&providedids);
1954 }
1955 
1956 /**
1957  * dnf_sack_make_provides_ready:
1958  * @sack: a #DnfSack instance.
1959  *
1960  * Gets the sack ready for depsolving.
1961  *
1962  * Since: 0.7.0
1963  */
1964 void
dnf_sack_make_provides_ready(DnfSack * sack)1965 dnf_sack_make_provides_ready(DnfSack *sack)
1966 {
1967     DnfSackPrivate *priv = GET_PRIVATE(sack);
1968 
1969     if (priv->provides_ready)
1970         return;
1971     repo_internalize_all_trigger(priv->pool);
1972     Queue addedfileprovides;
1973     Queue addedfileprovides_inst;
1974     queue_init(&addedfileprovides);
1975     queue_init(&addedfileprovides_inst);
1976     pool_addfileprovides_queue(priv->pool, &addedfileprovides,
1977                                &addedfileprovides_inst);
1978     if (addedfileprovides.count || addedfileprovides_inst.count)
1979         rewrite_repos(sack, &addedfileprovides, &addedfileprovides_inst);
1980     queue_free(&addedfileprovides);
1981     queue_free(&addedfileprovides_inst);
1982     pool_createwhatprovides(priv->pool);
1983     priv->provides_ready = 1;
1984 }
1985 
1986 /**
1987  * dnf_sack_running_kernel: (skip)
1988  * @sack: a #DnfSack instance.
1989  *
1990  * Returns the ID of the running kernel.
1991  *
1992  * Returns: an #Id or 0
1993  *
1994  * Since: 0.7.0
1995  */
1996 Id
dnf_sack_running_kernel(DnfSack * sack)1997 dnf_sack_running_kernel(DnfSack *sack)
1998 {
1999     DnfSackPrivate *priv = GET_PRIVATE(sack);
2000     if (priv->running_kernel_id >= 0)
2001         return priv->running_kernel_id;
2002     if (priv->running_kernel_fn)
2003         priv->running_kernel_id = priv->running_kernel_fn(sack);
2004     return priv->running_kernel_id;
2005 }
2006 
2007 /**
2008  * dnf_sack_get_pool: (skip)
2009  * @sack: a #DnfSack instance.
2010  *
2011  * Gets the internal pool for the sack.
2012  *
2013  * Returns: The pool, which is always set
2014  *
2015  * Since: 0.7.0
2016  */
2017 Pool *
dnf_sack_get_pool(DnfSack * sack)2018 dnf_sack_get_pool(DnfSack *sack)
2019 {
2020     DnfSackPrivate *priv = GET_PRIVATE(sack);
2021     return priv->pool;
2022 }
2023 
2024 /**
2025  * dnf_sack_set_module_container: (skip)
2026  * @sack: a #DnfSack instance.
2027  *
2028  * Sets the internal ModulePackageContainer.
2029  *
2030  * Returns: The old ModulePackageContainer, that has to be freed manually.
2031  *
2032  * Since: 0.31.0
2033  */
2034 libdnf::ModulePackageContainer *
dnf_sack_set_module_container(DnfSack * sack,libdnf::ModulePackageContainer * newConteiner)2035 dnf_sack_set_module_container(DnfSack *sack, libdnf::ModulePackageContainer * newConteiner)
2036 {
2037     DnfSackPrivate *priv = GET_PRIVATE(sack);
2038     auto oldConteiner = priv->moduleContainer;
2039     priv->moduleContainer = newConteiner;
2040     return oldConteiner;
2041 }
2042 
2043 /**
2044  * dnf_sack_get_module_container: (skip)
2045  * @sack: a #DnfSack instance.
2046  *
2047  * Gets the internal ModulePackageContainer.
2048  *
2049  * Returns: The ModulePackageContainer, that can be not set
2050  *
2051  * Since: 0.16.3
2052  */
2053 libdnf::ModulePackageContainer *
dnf_sack_get_module_container(DnfSack * sack)2054 dnf_sack_get_module_container(DnfSack *sack)
2055 {
2056     DnfSackPrivate *priv = GET_PRIVATE(sack);
2057     return priv->moduleContainer;
2058 }
2059 
2060 /**********************************************************************/
2061 
2062 static void
process_excludes(DnfSack * sack,GPtrArray * enabled_repos)2063 process_excludes(DnfSack *sack, GPtrArray *enabled_repos)
2064 {
2065     auto & mainConf = libdnf::getGlobalMainConfig();
2066     auto & disabled = mainConf.disable_excludes().getValue();
2067 
2068     if (std::find(disabled.begin(), disabled.end(), "all") != disabled.end()) {
2069         return;
2070     }
2071 
2072     libdnf::PackageSet repoIncludes(sack);
2073     libdnf::PackageSet repoExcludes(sack);
2074     bool includesExist = false;
2075 
2076     for (guint i = 0; i < enabled_repos->len; i++) {
2077         auto dnfRepo = static_cast<DnfRepo *>(enabled_repos->pdata[i]);
2078         auto repo = dnf_repo_get_repo(dnfRepo);
2079         if (std::find(disabled.begin(), disabled.end(), repo->getId()) != disabled.end()) {
2080             continue;
2081         }
2082 
2083         libdnf::Query repoQuery(sack);
2084         repoQuery.addFilter(HY_PKG_REPONAME, HY_EQ, repo->getId().c_str());
2085         repoQuery.apply();
2086 
2087         for (const auto & name : repo->getConfig()->includepkgs().getValue()) {
2088             libdnf::Query query(repoQuery);
2089             auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
2090             if (ret.first) {
2091                 repoIncludes += *query.runSet();
2092                 includesExist = true;
2093                 repo->setUseIncludes(true);
2094             }
2095         }
2096 
2097         for (const auto & name : repo->getConfig()->excludepkgs().getValue()) {
2098             libdnf::Query query(repoQuery);
2099             auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
2100             if (ret.first) {
2101                 repoExcludes += *query.runSet();
2102             }
2103         }
2104     }
2105 
2106     if (std::find(disabled.begin(), disabled.end(), "main") == disabled.end()) {
2107         bool useGlobalIncludes = false;
2108         for (const auto & name : mainConf.includepkgs().getValue()) {
2109             libdnf::Query query(sack);
2110             auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
2111             if (ret.first) {
2112                 repoIncludes += *query.runSet();
2113                 includesExist = true;
2114                 useGlobalIncludes = true;
2115             }
2116         }
2117 
2118         for (const auto & name : mainConf.excludepkgs().getValue()) {
2119             libdnf::Query query(sack);
2120             auto ret = query.filterSubject(name.c_str(), nullptr, false, true, false, false);
2121             if (ret.first) {
2122                 repoExcludes += *query.runSet();
2123             }
2124         }
2125 
2126         if (useGlobalIncludes) {
2127             dnf_sack_set_use_includes(sack, nullptr, true);
2128         }
2129     }
2130 
2131     if (includesExist) {
2132         dnf_sack_add_includes(sack, &repoIncludes);
2133     }
2134     dnf_sack_add_excludes(sack, &repoExcludes);
2135 }
2136 
2137 /**
2138  * dnf_sack_add_repo:
2139  */
2140 gboolean
dnf_sack_add_repo(DnfSack * sack,DnfRepo * repo,guint permissible_cache_age,DnfSackAddFlags flags,DnfState * state,GError ** error)2141 dnf_sack_add_repo(DnfSack *sack,
2142                     DnfRepo *repo,
2143                     guint permissible_cache_age,
2144                     DnfSackAddFlags flags,
2145                     DnfState *state,
2146                     GError **error) try
2147 {
2148     gboolean ret = TRUE;
2149     GError *error_local = NULL;
2150     DnfState *state_local;
2151     int flags_hy = DNF_SACK_LOAD_FLAG_BUILD_CACHE;
2152 
2153     /* set state */
2154     ret = dnf_state_set_steps(state, error,
2155                    5, /* check repo */
2156                    95, /* load solv */
2157                    -1);
2158     if (!ret)
2159         return FALSE;
2160 
2161     /* check repo */
2162     state_local = dnf_state_get_child(state);
2163     ret = dnf_repo_check(repo,
2164                          permissible_cache_age,
2165                          state_local,
2166                          &error_local);
2167     if (!ret) {
2168         g_debug("failed to check, attempting update: %s",
2169                 error_local->message);
2170         g_clear_error(&error_local);
2171         dnf_state_reset(state_local);
2172         ret = dnf_repo_update(repo,
2173                               DNF_REPO_UPDATE_FLAG_FORCE,
2174                               state_local,
2175                               &error_local);
2176         if (!ret) {
2177             if (!dnf_repo_get_required(repo) &&
2178                 (g_error_matches(error_local,
2179                                  DNF_ERROR,
2180                                  DNF_ERROR_CANNOT_FETCH_SOURCE) ||
2181                  g_error_matches(error_local,
2182                                  DNF_ERROR,
2183                                  DNF_ERROR_REPO_NOT_AVAILABLE))) {
2184                 g_warning("Skipping refresh of %s: %s",
2185                           dnf_repo_get_id(repo),
2186                           error_local->message);
2187                 g_error_free(error_local);
2188                 return dnf_state_finished(state, error);
2189             }
2190             g_propagate_error(error, error_local);
2191             return FALSE;
2192         }
2193     }
2194 
2195     /* checking disabled the repo */
2196     if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_NONE) {
2197         g_debug("Skipping %s as repo no longer enabled",
2198                 dnf_repo_get_id(repo));
2199         return dnf_state_finished(state, error);
2200     }
2201 
2202     /* done */
2203     if (!dnf_state_done(state, error))
2204         return FALSE;
2205 
2206     /* only load what's required */
2207     if ((flags & DNF_SACK_ADD_FLAG_FILELISTS) > 0)
2208         flags_hy |= DNF_SACK_LOAD_FLAG_USE_FILELISTS;
2209     if ((flags & DNF_SACK_ADD_FLAG_OTHER) > 0)
2210         flags_hy |= DNF_SACK_LOAD_FLAG_USE_OTHER;
2211     if ((flags & DNF_SACK_ADD_FLAG_UPDATEINFO) > 0)
2212         flags_hy |= DNF_SACK_LOAD_FLAG_USE_UPDATEINFO;
2213 
2214     /* load solv */
2215     g_debug("Loading repo %s", dnf_repo_get_id(repo));
2216     dnf_state_action_start(state, DNF_STATE_ACTION_LOADING_CACHE, NULL);
2217     if (!dnf_sack_load_repo(sack, dnf_repo_get_repo(repo), flags_hy, error))
2218         return FALSE;
2219 
2220     /* done */
2221     return dnf_state_done(state, error);
2222 } CATCH_TO_GERROR(FALSE)
2223 
2224 /**
2225  * dnf_sack_add_repos:
2226  */
2227 gboolean
2228 dnf_sack_add_repos(DnfSack *sack,
2229                      GPtrArray *repos,
2230                      guint permissible_cache_age,
2231                      DnfSackAddFlags flags,
2232                      DnfState *state,
2233                      GError **error) try
2234 {
2235     gboolean ret;
2236     guint cnt = 0;
2237     guint i;
2238     DnfRepo *repo;
2239     DnfState *state_local;
2240     g_autoptr(GPtrArray) enabled_repos = g_ptr_array_new();
2241 
2242     /* count the enabled repos */
2243     for (i = 0; i < repos->len; i++) {
2244         repo = static_cast<DnfRepo *>(g_ptr_array_index(repos, i));
2245         if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_NONE)
2246             continue;
2247 
2248         /* only allow metadata-only repos if FLAG_UNAVAILABLE is set */
2249         if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_METADATA) {
2250             if ((flags & DNF_SACK_ADD_FLAG_UNAVAILABLE) == 0)
2251                 continue;
2252         }
2253 
2254         cnt++;
2255     }
2256 
2257     /* add each repo */
2258     dnf_state_set_number_steps(state, cnt);
2259     for (i = 0; i < repos->len; i++) {
2260         repo = static_cast<DnfRepo *>(g_ptr_array_index(repos, i));
2261         if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_NONE)
2262             continue;
2263 
2264         /* only allow metadata-only repos if FLAG_UNAVAILABLE is set */
2265         if (dnf_repo_get_enabled(repo) == DNF_REPO_ENABLED_METADATA) {
2266             if ((flags & DNF_SACK_ADD_FLAG_UNAVAILABLE) == 0)
2267                 continue;
2268         }
2269 
2270         state_local = dnf_state_get_child(state);
2271         ret = dnf_sack_add_repo(sack,
2272                                   repo,
2273                                   permissible_cache_age,
2274                                   flags,
2275                                   state_local,
2276                                   error);
2277         if (!ret)
2278             return FALSE;
2279 
2280         g_ptr_array_add(enabled_repos, repo);
2281 
2282         /* done */
2283         if (!dnf_state_done(state, error))
2284             return FALSE;
2285     }
2286 
2287     process_excludes(sack, enabled_repos);
2288 
2289     /* success */
2290     return TRUE;
2291 } CATCH_TO_GERROR(FALSE)
2292 
2293 namespace {
readModuleMetadataFromRepo(DnfSack * sack,libdnf::ModulePackageContainer * modulePackages,const char * platformModule)2294 void readModuleMetadataFromRepo(DnfSack * sack, libdnf::ModulePackageContainer * modulePackages,
2295     const char * platformModule)
2296 {
2297     modulePackages->add(sack);
2298     modulePackages->loadFailSafeData();
2299     if (!modulePackages->empty()) {
2300         // TODO remove hard-coded path
2301         try {
2302             std::vector<std::string> paths{"/etc/os-release", "/usr/lib/os-release"};
2303             modulePackages->addPlatformPackage(sack, paths, platformModule);
2304         } catch (const std::exception & except) {
2305             auto logger(libdnf::Log::getLogger());
2306             logger->critical("Detection of Platform Module failed: " + std::string(except.what()));
2307         }
2308     }
2309 }
2310 
2311 /// @return std::map<name:stream.arch, std::vector<std::string>>
getDemodularizedRpms(libdnf::ModulePackageContainer & moduleContainer,const std::vector<libdnf::ModulePackage * > & allPackages)2312 static std::map<std::string, std::vector<std::string>> getDemodularizedRpms(
2313     libdnf::ModulePackageContainer & moduleContainer, const std::vector<libdnf::ModulePackage *> & allPackages)
2314 {
2315     std::map<std::string, std::vector<std::string>> ret;
2316     auto latest = moduleContainer.getLatestModules(allPackages, true);
2317     for (auto modulePackage : latest) {
2318         auto demodularized = modulePackage->getDemodularizedRpms();
2319         if (demodularized.empty()) {
2320             continue;
2321         }
2322         std::string packageID{modulePackage->getNameStream()};
2323         packageID.append(".");
2324         packageID.append(modulePackage->getArch());
2325         auto & data = ret[packageID];
2326         data.insert(data.end(), demodularized.begin(), demodularized.end());
2327     }
2328     return ret;
2329 }
2330 
2331 /// Return <includeNEVRAs>, <excludeNEVRAs>, <names>, <srcNames>, <name dependency container>
2332 static std::tuple<std::vector<std::string>, std::vector<std::string>, std::vector<std::string>, std::vector<std::string>, libdnf::DependencyContainer>
collectNevraForInclusionExclusion(DnfSack * sack,libdnf::ModulePackageContainer & modulePackageContainer)2333 collectNevraForInclusionExclusion(DnfSack *sack, libdnf::ModulePackageContainer &modulePackageContainer)
2334 {
2335     auto allPackages = modulePackageContainer.getModulePackages();
2336     auto demodularizedNames = getDemodularizedRpms(modulePackageContainer, allPackages);
2337 
2338     std::vector<std::string> includeNEVRAs;
2339     std::vector<std::string> excludeNEVRAs;
2340     std::vector<std::string> names;
2341     std::vector<std::string> srcNames;
2342     libdnf::DependencyContainer nameDependencies{sack};
2343     libdnf::Nevra nevra;
2344     // TODO: turn into std::vector<const char *> to prevent unnecessary conversion?
2345     for (const auto & module : allPackages) {
2346         auto artifacts = module->getArtifacts();
2347         // TODO use Goal::listInstalls() to not requires filtering out Platform
2348         if (modulePackageContainer.isModuleActive(module->getId())) {
2349             std::string packageID{module->getNameStream()};
2350             packageID.append(".");
2351             packageID.append(module->getArch());
2352             auto it = demodularizedNames.find(packageID);
2353             if (it == demodularizedNames.end()) {
2354                 for (const auto &rpm : artifacts) {
2355                     if (nevra.parse(rpm.c_str(), HY_FORM_NEVRA)) {
2356                         auto arch = nevra.getArch();
2357                         // source packages do not provide anything and must not cause excluding binary packages
2358                         if (arch == "src" || arch == "nosrc") {
2359                             srcNames.push_back(nevra.getName());
2360                         } else {
2361                             names.push_back(nevra.getName());
2362                             nameDependencies.addReldep(nevra.getName().c_str());
2363                         }
2364                     }
2365                 }
2366             } else {
2367                 for (const auto &rpm : artifacts) {
2368                     if (nevra.parse(rpm.c_str(), HY_FORM_NEVRA)) {
2369                         bool found = false;
2370                         for ( auto & demodularized : it->second) {
2371                             if (nevra.getName() == demodularized) {
2372                                 found = true;
2373                                 break;
2374                             }
2375                         }
2376                         if (found) {
2377                             continue;
2378                         }
2379                         auto arch = nevra.getArch();
2380                         // source packages do not provide anything and must not cause excluding binary packages
2381                         if (arch == "src" || arch == "nosrc") {
2382                             srcNames.push_back(nevra.getName());
2383                         } else {
2384                             names.push_back(nevra.getName());
2385                             nameDependencies.addReldep(nevra.getName().c_str());
2386                         }
2387                     }
2388                 }
2389             }
2390             copy(std::begin(artifacts), std::end(artifacts), std::back_inserter(includeNEVRAs));
2391         } else {
2392             copy(std::begin(artifacts), std::end(artifacts), std::back_inserter(excludeNEVRAs));
2393         }
2394     }
2395 
2396     return std::make_tuple(std::move(includeNEVRAs), std::move(excludeNEVRAs), std::move(names), std::move(srcNames),
2397                            std::move(nameDependencies));
2398 }
2399 
2400 void
setModuleExcludes(DnfSack * sack,const char ** hotfixRepos,libdnf::ModulePackageContainer & modulePackageContainer)2401 setModuleExcludes(DnfSack * sack, const char ** hotfixRepos, libdnf::ModulePackageContainer & modulePackageContainer)
2402 {
2403     dnf_sack_set_module_excludes(sack, nullptr);
2404 
2405     auto data = collectNevraForInclusionExclusion(sack, modulePackageContainer);
2406 
2407     auto & includeNEVRAs = std::get<0>(data);
2408     auto & excludeNEVRAs = std::get<1>(data);
2409     auto & names = std::get<2>(data);
2410     auto & srcNames = std::get<3>(data);
2411     auto & nameDependencies = std::get<4>(data);
2412 
2413     std::vector<const char *> namesCString(names.size() + 1);
2414     std::vector<const char *> srcNamesCString(srcNames.size() + 1);
2415     std::vector<const char *> excludeNEVRAsCString(excludeNEVRAs.size() + 1);
2416     std::vector<const char *> includeNEVRAsCString(includeNEVRAs.size() + 1);
2417 
2418     transform(names.begin(), names.end(), namesCString.begin(), std::mem_fn(&std::string::c_str));
2419     transform(srcNames.begin(), srcNames.end(), srcNamesCString.begin(), std::mem_fn(&std::string::c_str));
2420     transform(excludeNEVRAs.begin(), excludeNEVRAs.end(), excludeNEVRAsCString.begin(),
2421               std::mem_fn(&std::string::c_str));
2422     transform(includeNEVRAs.begin(), includeNEVRAs.end(), includeNEVRAsCString.begin(),
2423               std::mem_fn(&std::string::c_str));
2424 
2425     libdnf::Query keepPackages{sack};
2426     const char *keepRepo[] = {HY_CMDLINE_REPO_NAME, HY_SYSTEM_REPO_NAME, nullptr};
2427     keepPackages.addFilter(HY_PKG_REPONAME, HY_NEQ, keepRepo);
2428     if (hotfixRepos != nullptr) {
2429         keepPackages.addFilter(HY_PKG_REPONAME, HY_NEQ, hotfixRepos);
2430     }
2431 
2432     libdnf::Query includeQuery{sack};
2433     libdnf::Query excludeQuery{keepPackages};
2434     libdnf::Query excludeProvidesQuery{keepPackages};
2435     libdnf::Query excludeNamesQuery(keepPackages);
2436     libdnf::Query excludeSrcNamesQuery(keepPackages);
2437     includeQuery.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, includeNEVRAsCString.data());
2438 
2439     excludeQuery.addFilter(HY_PKG_NEVRA_STRICT, HY_EQ, excludeNEVRAsCString.data());
2440     excludeQuery.queryDifference(includeQuery);
2441 
2442     // Exclude packages by their Provides
2443     excludeProvidesQuery.addFilter(HY_PKG_PROVIDES, &nameDependencies);
2444     excludeProvidesQuery.queryDifference(includeQuery);
2445 
2446     // Search for source packages with same names as included source artifacts
2447     excludeSrcNamesQuery.addFilter(HY_PKG_NAME, HY_EQ, srcNamesCString.data());
2448     const char * srcArchs[] = {"src", "nosrc", nullptr};
2449     excludeSrcNamesQuery.addFilter(HY_PKG_ARCH, HY_EQ, srcArchs);
2450 
2451     // Required to filtrate out source packages and packages with incompatible architectures
2452     excludeNamesQuery.addFilter(HY_PKG_NAME, HY_EQ, namesCString.data());
2453     excludeNamesQuery.queryUnion(excludeSrcNamesQuery);
2454     excludeNamesQuery.queryDifference(includeQuery);
2455 
2456     dnf_sack_set_module_excludes(sack, excludeQuery.getResultPset());
2457     dnf_sack_add_module_excludes(sack, excludeProvidesQuery.getResultPset());
2458     dnf_sack_add_module_excludes(sack, excludeNamesQuery.getResultPset());
2459     dnf_sack_set_module_includes(sack, includeQuery.getResultPset());
2460 }
2461 
2462 }
2463 
requiresModuleEnablement(DnfSack * sack,const libdnf::PackageSet * installSet)2464 std::vector<libdnf::ModulePackage *> requiresModuleEnablement(
2465     DnfSack * sack, const libdnf::PackageSet * installSet)
2466 {
2467     DnfSackPrivate *priv = GET_PRIVATE(sack);
2468     if (!priv->module_includes || !priv->moduleContainer) {
2469         return {};
2470     }
2471     libdnf::PackageSet tmp(sack);
2472     tmp += *const_cast<libdnf::PackageSet*>(installSet);
2473     tmp /= priv->module_includes;
2474 
2475     if (tmp.empty()) {
2476         return {};
2477     }
2478     auto toEnable = priv->moduleContainer->requiresModuleEnablement(*installSet);
2479     return toEnable;
2480 }
2481 
dnf_sack_filter_modules(DnfSack * sack,GPtrArray * repos,const char * install_root,const char * platformModule)2482 void dnf_sack_filter_modules(DnfSack *sack, GPtrArray *repos, const char *install_root,
2483     const char * platformModule)
2484 {
2485     std::vector<const char *> hotfixRepos;
2486     // don't filter RPMs from repos with the 'module_hotfixes' flag set
2487     for (unsigned int i = 0; i < repos->len; i++) {
2488         auto repo = static_cast<DnfRepo *>(g_ptr_array_index(repos, i));
2489         if (dnf_repo_get_module_hotfixes(repo)) {
2490             hotfixRepos.push_back(dnf_repo_get_id(repo));
2491         }
2492     }
2493     hotfixRepos.push_back(nullptr);
2494     dnf_sack_filter_modules_v2(sack, nullptr, hotfixRepos.data(), install_root, platformModule,
2495                                false, false, false);
2496 }
2497 
dnf_sack_filter_modules_v2(DnfSack * sack,DnfModulePackageContainer * moduleContainer,const char ** hotfixRepos,const char * install_root,const char * platformModule,bool updateOnly,bool debugSolver,bool applyObsoletes)2498 std::pair<std::vector<std::vector<std::string>>, libdnf::ModulePackageContainer::ModuleErrorType> dnf_sack_filter_modules_v2(
2499     DnfSack * sack, DnfModulePackageContainer * moduleContainer, const char ** hotfixRepos,
2500     const char * install_root, const char * platformModule, bool updateOnly, bool debugSolver, bool applyObsoletes)
2501 {
2502     if (!updateOnly) {
2503         if (!install_root) {
2504             throw std::runtime_error("Installroot not provided");
2505         }
2506         DnfSackPrivate *priv = GET_PRIVATE(sack);
2507         if (!moduleContainer) {
2508             if (priv->moduleContainer) {
2509                 delete priv->moduleContainer;
2510             }
2511             priv->moduleContainer = new libdnf::ModulePackageContainer(dnf_sack_get_all_arch(sack),
2512                 install_root, dnf_sack_get_arch(sack));
2513             moduleContainer = priv->moduleContainer;
2514         }
2515         readModuleMetadataFromRepo(sack, moduleContainer, platformModule);
2516         moduleContainer->addDefaultsFromDisk();
2517 
2518         try {
2519             moduleContainer->moduleDefaultsResolve();
2520         } catch (libdnf::ModulePackageContainer::ResolveException & exception) {
2521             auto logger(libdnf::Log::getLogger());
2522             logger->debug(tfm::format(_("No module defaults found: %s"), exception.what()));
2523         }
2524     }
2525 
2526     if (!moduleContainer) {
2527         throw std::runtime_error("ModuleContainer not provided");
2528     }
2529 
2530     if (applyObsoletes) {
2531         moduleContainer->applyObsoletes();
2532     }
2533     auto ret = moduleContainer->resolveActiveModulePackages(debugSolver);
2534 
2535     setModuleExcludes(sack, hotfixRepos, *moduleContainer);
2536     return ret;
2537 }
2538 
dnf_sack_get_rpmdb_version(DnfSack * sack)2539 std::string dnf_sack_get_rpmdb_version(DnfSack *sack) {
2540     // collect all sha1hdr checksums
2541     // they are sufficiently unique IDs that represent installed RPMs
2542     std::vector<std::string> checksums;
2543 
2544     // iterate all @System repo RPMs (rpmdb records)
2545     libdnf::Query query{sack, libdnf::Query::ExcludeFlags::IGNORE_EXCLUDES};
2546     query.installed();
2547 
2548     auto pset = query.getResultPset();
2549     Id id = -1;
2550     while(true) {
2551         id = pset->next(id);
2552         if (id == -1) {
2553             break;
2554         }
2555         DnfPackage *pkg = dnf_package_new(sack, id);
2556         // store pkgid (equals to sha1hdr)
2557         checksums.push_back(libdnf::string::fromCstring(dnf_package_get_pkgid(pkg)));
2558         g_object_unref(pkg);
2559     }
2560 
2561     // sort checksums to compute the output checksum always the same
2562     std::sort(checksums.begin(), checksums.end());
2563 
2564     SHA1Hash h;
2565     for (auto & checksum : checksums) {
2566         h.update(checksum.c_str());
2567     }
2568 
2569     // build <count>:<hash> output
2570     std::ostringstream result;
2571     result << checksums.size();
2572     result << ":";
2573     result << h.hexdigest();
2574 
2575     return result.str();
2576 }
2577