]> git.ipfire.org Git - people/stevee/pakfire.git/blob - src/libpakfire/package.c
filelist: Add flags argument to walk function
[people/stevee/pakfire.git] / src / libpakfire / package.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2013 Pakfire development team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <errno.h>
22 #include <linux/limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <uuid/uuid.h>
27
28 #include <json.h>
29
30 #include <solv/evr.h>
31 #include <solv/pool.h>
32 #include <solv/repo.h>
33 #include <solv/solvable.h>
34
35 #include <pakfire/archive.h>
36 #include <pakfire/constants.h>
37 #include <pakfire/dependencies.h>
38 #include <pakfire/digest.h>
39 #include <pakfire/file.h>
40 #include <pakfire/filelist.h>
41 #include <pakfire/i18n.h>
42 #include <pakfire/logging.h>
43 #include <pakfire/package.h>
44 #include <pakfire/pakfire.h>
45 #include <pakfire/private.h>
46 #include <pakfire/repo.h>
47 #include <pakfire/string.h>
48 #include <pakfire/util.h>
49
50 struct pakfire_package {
51 struct pakfire* pakfire;
52 int nrefs;
53
54 // Reference to this package in the SOLV pool
55 Id id;
56 struct pakfire_repo* repo;
57
58 char nevra[NAME_MAX];
59 char source_nevra[NAME_MAX];
60
61 char filename[NAME_MAX];
62 char path[PATH_MAX];
63 };
64
65 static Solvable* get_solvable(struct pakfire_package* pkg) {
66 Pool* pool = pakfire_get_solv_pool(pkg->pakfire);
67
68 return pool_id2solvable(pool, pkg->id);
69 }
70
71 static int pakfire_package_dep2id(const enum pakfire_package_key key,
72 Id* id, Id* marker) {
73 switch (key) {
74 case PAKFIRE_PKG_PROVIDES:
75 *id = SOLVABLE_PROVIDES;
76 *marker = -SOLVABLE_FILEMARKER;
77 break;
78
79 case PAKFIRE_PKG_PREREQUIRES:
80 *id = SOLVABLE_REQUIRES;
81 *marker = SOLVABLE_PREREQMARKER;
82 break;
83
84 case PAKFIRE_PKG_REQUIRES:
85 *id = SOLVABLE_REQUIRES;
86 *marker = -SOLVABLE_PREREQMARKER;
87 break;
88
89 case PAKFIRE_PKG_CONFLICTS:
90 *id = SOLVABLE_CONFLICTS;
91 break;
92
93 case PAKFIRE_PKG_OBSOLETES:
94 *id = SOLVABLE_OBSOLETES;
95 break;
96
97 case PAKFIRE_PKG_RECOMMENDS:
98 *id = SOLVABLE_RECOMMENDS;
99 break;
100
101 case PAKFIRE_PKG_SUGGESTS:
102 *id = SOLVABLE_SUGGESTS;
103 break;
104
105 case PAKFIRE_PKG_SUPPLEMENTS:
106 *id = SOLVABLE_SUPPLEMENTS;
107 break;
108
109 case PAKFIRE_PKG_ENHANCES:
110 *id = SOLVABLE_ENHANCES;
111 break;
112
113 // This operation is not possible for any other types
114 default:
115 errno = EINVAL;
116 return 1;
117 }
118
119 return 0;
120 }
121
122 static int pakfire_package_add_depid(struct pakfire_package* pkg,
123 const enum pakfire_package_key key, Id dep) {
124 Solvable* s = get_solvable(pkg);
125 int r;
126
127 Id id = ID_NULL;
128 Id marker = ID_NULL;
129
130 // Translate the dependency type
131 r = pakfire_package_dep2id(key, &id, &marker);
132 if (r)
133 return r;
134
135 // Append to the dependency array
136 solvable_add_deparray(s, id, dep, marker);
137
138 return 0;
139 }
140
141 static int pakfire_package_add_self_provides(struct pakfire_package* pkg) {
142 // Fetch the solvable
143 Solvable* s = get_solvable(pkg);
144 if (!s)
145 return 1;
146
147 // Get the self-provides ID
148 Id dep = solvable_selfprovidedep(s);
149
150 // Add it to the package
151 return pakfire_package_add_depid(pkg, PAKFIRE_PKG_PROVIDES, dep);
152 }
153
154 int pakfire_package_create_from_solvable(struct pakfire_package** package,
155 struct pakfire* pakfire, Id id) {
156 struct pakfire_package* pkg = calloc(1, sizeof(*pkg));
157 if (!pkg)
158 return 1;
159
160 pkg->pakfire = pakfire_ref(pakfire);
161 pkg->nrefs = 1;
162
163 // Store the ID
164 pkg->id = id;
165
166 // Success
167 *package = pkg;
168 return 0;
169 }
170
171 PAKFIRE_EXPORT int pakfire_package_create(struct pakfire_package** package,
172 struct pakfire* pakfire, struct pakfire_repo* repo,
173 const char* name, const char* evr, const char* arch) {
174 struct pakfire_repo* dummy = NULL;
175 int r;
176
177 // Check for some valid input
178 if (!name || !evr || !arch) {
179 errno = EINVAL;
180 return 1;
181 }
182
183 // Default to dummy repository
184 if (!repo) {
185 dummy = pakfire_get_repo(pakfire, PAKFIRE_REPO_DUMMY);
186 if (!dummy) {
187 errno = ENOENT;
188 return 1;
189 }
190
191 repo = dummy;
192 }
193
194 // Allocate a new solvable
195 Id id = pakfire_repo_add_solvable(repo);
196 if (!id) {
197 ERROR(pakfire, "Could not allocate a solvable: %m\n");
198 r = 1;
199 goto ERROR;
200 }
201
202 // Create a new package object
203 r = pakfire_package_create_from_solvable(package, pakfire, id);
204 if (r)
205 goto ERROR;
206
207 // Reference the repository
208 (*package)->repo = pakfire_repo_ref(repo);
209
210 // Set the name
211 r = pakfire_package_set_string(*package, PAKFIRE_PKG_NAME, name);
212 if (r) {
213 ERROR(pakfire, "Could not set package name '%s': %m\n", name);
214 goto ERROR;
215 }
216
217 // Set EVR
218 r = pakfire_package_set_string(*package, PAKFIRE_PKG_EVR, evr);
219 if (r) {
220 ERROR(pakfire, "Could not set package EVR '%s': %m\n", evr);
221 goto ERROR;
222 }
223
224 // Set arch
225 r = pakfire_package_set_string(*package, PAKFIRE_PKG_ARCH, arch);
226 if (r) {
227 ERROR(pakfire, "Could not set package arch '%s': %m\n", arch);
228 goto ERROR;
229 }
230
231 // Add self-provides
232 r = pakfire_package_add_self_provides(*package);
233 if (r) {
234 ERROR(pakfire, "Could not create self-provides: %m\n");
235 goto ERROR;
236 }
237
238 ERROR:
239 if (dummy)
240 pakfire_repo_unref(dummy);
241
242 return r;
243 }
244
245 static void pakfire_package_free(struct pakfire_package* pkg) {
246 if (pkg->repo)
247 pakfire_repo_unref(pkg->repo);
248
249 pakfire_unref(pkg->pakfire);
250 free(pkg);
251 }
252
253 PAKFIRE_EXPORT struct pakfire_package* pakfire_package_ref(struct pakfire_package* pkg) {
254 pkg->nrefs++;
255
256 return pkg;
257 }
258
259 PAKFIRE_EXPORT struct pakfire_package* pakfire_package_unref(struct pakfire_package* pkg) {
260 if (--pkg->nrefs > 0)
261 return pkg;
262
263 pakfire_package_free(pkg);
264 return NULL;
265 }
266
267 PAKFIRE_EXPORT struct pakfire* pakfire_package_get_pakfire(struct pakfire_package* pkg) {
268 return pakfire_ref(pkg->pakfire);
269 }
270
271 PAKFIRE_EXPORT int pakfire_package_eq(struct pakfire_package* pkg1, struct pakfire_package* pkg2) {
272 return pkg1->id == pkg2->id;
273 }
274
275 PAKFIRE_EXPORT int pakfire_package_cmp(struct pakfire_package* pkg1, struct pakfire_package* pkg2) {
276 Pool* pool = pakfire_get_solv_pool(pkg1->pakfire);
277
278 Solvable* s1 = get_solvable(pkg1);
279 Solvable* s2 = get_solvable(pkg2);
280
281 // Check names
282 const char* str1 = pool_id2str(pool, s1->name);
283 const char* str2 = pool_id2str(pool, s2->name);
284
285 int ret = strcmp(str1, str2);
286 if (ret)
287 return ret;
288
289 // Check the version string
290 ret = pakfire_package_evr_cmp(pkg1, pkg2);
291 if (ret)
292 return ret;
293
294 // Check repositories
295 struct pakfire_repo* repo1 = pakfire_package_get_repo(pkg1);
296 struct pakfire_repo* repo2 = pakfire_package_get_repo(pkg2);
297
298 if (repo1 && repo2) {
299 ret = pakfire_repo_cmp(repo1, repo2);
300 }
301
302 pakfire_repo_unref(repo1);
303 pakfire_repo_unref(repo2);
304
305 if (ret)
306 return ret;
307
308 // Check package architectures
309 str1 = pool_id2str(pool, s1->arch);
310 str2 = pool_id2str(pool, s2->arch);
311
312 return strcmp(str1, str2);
313 }
314
315 PAKFIRE_EXPORT int pakfire_package_evr_cmp(struct pakfire_package* pkg1, struct pakfire_package* pkg2) {
316 Pool* pool = pakfire_get_solv_pool(pkg1->pakfire);
317
318 Solvable* s1 = get_solvable(pkg1);
319 Solvable* s2 = get_solvable(pkg2);
320
321 return pool_evrcmp(pool, s1->evr, s2->evr, EVRCMP_COMPARE);
322 }
323
324 PAKFIRE_EXPORT unsigned int pakfire_package_id(struct pakfire_package* pkg) {
325 return pkg->id;
326 }
327
328 char* pakfire_package_join_evr(const char* e, const char* v, const char* r) {
329 char* buffer = NULL;
330
331 // Check for valid input
332 if (!e || !v || !r) {
333 errno = EINVAL;
334 return NULL;
335 }
336
337 // Skip any zeroes in epoch
338 while (*e && *e == '0')
339 e++;
340
341 // Format string with epoch
342 if (*e) {
343 if (asprintf(&buffer, "%s:%s-%s", e, v, r) < 0)
344 return NULL;
345
346 // Or format it without epoch
347 } else {
348 if (asprintf(&buffer, "%s-%s", v, r) < 0)
349 return NULL;
350 }
351
352 return buffer;
353 }
354
355 int pakfire_package_is_source(struct pakfire_package* pkg) {
356 const char* arch = pakfire_package_get_string(pkg, PAKFIRE_PKG_ARCH);
357 if (!arch)
358 return 1;
359
360 return (strcmp(arch, "src") == 0);
361 }
362
363 static void pakfire_package_internalize_repo(struct pakfire_package* pkg) {
364 struct pakfire_repo* repo = pakfire_package_get_repo(pkg);
365 if (repo) {
366 pakfire_repo_internalize(repo, 0);
367 pakfire_repo_unref(repo);
368 }
369 }
370
371 static void pakfire_package_has_changed(struct pakfire_package* pkg) {
372 struct pakfire_repo* repo = pakfire_package_get_repo(pkg);
373 if (repo) {
374 pakfire_repo_has_changed(repo);
375 pakfire_repo_unref(repo);
376 }
377 }
378
379 // Removes epoch
380 static const char* evr2vr(const char* evr) {
381 const char* p = evr;
382
383 // Skip any leading digits
384 for (; *p >= '0' && *p <= '9'; p++);
385
386 // If after the leading digits, we found :, we return the rest of the string
387 if (p != evr && *p == ':')
388 return ++p;
389
390 return evr;
391 }
392
393 static const char* pakfire_package_make_filename(struct pakfire_package* pkg) {
394 int r;
395
396 if (!*pkg->filename) {
397 const char* name = pakfire_package_get_string(pkg, PAKFIRE_PKG_NAME);
398 const char* evr = pakfire_package_get_string(pkg, PAKFIRE_PKG_EVR);
399 const char* arch = pakfire_package_get_string(pkg, PAKFIRE_PKG_ARCH);
400
401 if (!name || !evr || !arch)
402 return NULL;
403
404 const char* vr = evr2vr(evr);
405 if (!vr)
406 return NULL;
407
408 r = pakfire_string_format(pkg->filename, "%s-%s.%s.pfm", name, vr, arch);
409 if (r)
410 return NULL;
411 }
412
413 return pkg->filename;
414 }
415
416 static int pakfire_package_make_cache_path(struct pakfire_package* pkg) {
417 const char* filename = pakfire_package_get_string(pkg, PAKFIRE_PKG_FILENAME);
418
419 enum pakfire_digest_types digest_type = PAKFIRE_DIGEST_UNDEFINED;
420 size_t digest_length = 0;
421
422 // Fetch the digest
423 const unsigned char* digest = pakfire_package_get_digest(pkg,
424 &digest_type, &digest_length);
425
426 if (digest && digest_length >= 4)
427 return pakfire_cache_path(pkg->pakfire, pkg->path,
428 "%02x/%02x/%02x/%02x/%s", digest[0], digest[1], digest[2], digest[3], filename);
429
430 return pakfire_cache_path(pkg->pakfire, pkg->path, "%s", filename);
431 }
432
433 PAKFIRE_EXPORT const char* pakfire_package_get_string(
434 struct pakfire_package* pkg, const enum pakfire_package_key key) {
435 const char* ret = NULL;
436 int r;
437
438 pakfire_package_internalize_repo(pkg);
439
440 Pool* pool = pakfire_get_solv_pool(pkg->pakfire);
441 Solvable* s = get_solvable(pkg);
442
443 switch (key) {
444 case PAKFIRE_PKG_NAME:
445 return pool_id2str(pool, s->name);
446
447 case PAKFIRE_PKG_EVR:
448 return pool_id2str(pool, s->evr);
449
450 case PAKFIRE_PKG_ARCH:
451 return pool_id2str(pool, s->arch);
452
453 case PAKFIRE_PKG_NEVRA:
454 if (!*pkg->nevra) {
455 r = pakfire_string_set(pkg->nevra, pool_solvable2str(pool, s));
456 if (r)
457 return NULL;
458 }
459
460 return pkg->nevra;
461
462 case PAKFIRE_PKG_UUID:
463 ret = solvable_lookup_str(s, SOLVABLE_PKGID);
464 break;
465
466 case PAKFIRE_PKG_SUMMARY:
467 ret = solvable_lookup_str(s, SOLVABLE_SUMMARY);
468 break;
469
470 case PAKFIRE_PKG_DESCRIPTION:
471 ret = solvable_lookup_str(s, SOLVABLE_DESCRIPTION);
472 break;
473
474 case PAKFIRE_PKG_LICENSE:
475 ret = solvable_lookup_str(s, SOLVABLE_LICENSE);
476 break;
477
478 case PAKFIRE_PKG_URL:
479 ret = solvable_lookup_str(s, SOLVABLE_URL);
480 break;
481
482 case PAKFIRE_PKG_GROUPS:
483 ret = solvable_lookup_str(s, SOLVABLE_GROUP);
484 break;
485
486 case PAKFIRE_PKG_VENDOR:
487 ret = solvable_lookup_str(s, SOLVABLE_VENDOR);
488 break;
489
490 case PAKFIRE_PKG_DISTRO:
491 ret = solvable_lookup_str(s, SOLVABLE_DISTRIBUTION);
492 break;
493
494 case PAKFIRE_PKG_PACKAGER:
495 ret = solvable_lookup_str(s, SOLVABLE_PACKAGER);
496 break;
497
498 case PAKFIRE_PKG_PATH:
499 if (!*pkg->path) {
500 const char* base = solvable_lookup_str(s, SOLVABLE_MEDIABASE);
501 if (base) {
502 const char* filename = pakfire_package_get_string(pkg, PAKFIRE_PKG_FILENAME);
503 if (!filename)
504 return NULL;
505
506 pakfire_string_format(pkg->path, "%s/%s", base, filename);
507 } else {
508 r = pakfire_package_make_cache_path(pkg);
509 if (r)
510 return NULL;
511 }
512 }
513
514 return pkg->path;
515
516 case PAKFIRE_PKG_FILENAME:
517 ret = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
518
519 // Generate the filename if not set
520 if (!ret)
521 ret = pakfire_package_make_filename(pkg);
522 break;
523
524 case PAKFIRE_PKG_BUILD_HOST:
525 ret = solvable_lookup_str(s, SOLVABLE_BUILDHOST);
526 break;
527
528 case PAKFIRE_PKG_BUILD_ID:
529 ret = solvable_lookup_str(s, SOLVABLE_BUILDVERSION);
530 break;
531
532 case PAKFIRE_PKG_SOURCE_PKG:
533 if (!*pkg->source_nevra) {
534 const char* name = pakfire_package_get_string(pkg, PAKFIRE_PKG_SOURCE_NAME);
535 const char* evr = pakfire_package_get_string(pkg, PAKFIRE_PKG_SOURCE_EVR);
536 const char* arch = pakfire_package_get_string(pkg, PAKFIRE_PKG_SOURCE_ARCH);
537
538 // Return nothing if we don't have all information
539 if (!name || !evr || !arch)
540 return NULL;
541
542 // Format package name
543 r = pakfire_string_format(pkg->source_nevra, "%s-%s.%s", name, evr, arch);
544 if (r)
545 return NULL;
546 }
547
548 return pkg->source_nevra;
549
550 case PAKFIRE_PKG_SOURCE_NAME:
551 ret = solvable_lookup_str(s, SOLVABLE_SOURCENAME);
552 break;
553
554 case PAKFIRE_PKG_SOURCE_EVR:
555 ret = solvable_lookup_str(s, SOLVABLE_SOURCEEVR);
556 break;
557
558 case PAKFIRE_PKG_SOURCE_ARCH:
559 ret = solvable_lookup_str(s, SOLVABLE_SOURCEARCH);
560 break;
561
562 default:
563 break;
564 }
565
566 return ret;
567 }
568
569 PAKFIRE_EXPORT int pakfire_package_set_string(
570 struct pakfire_package* pkg, const enum pakfire_package_key key, const char* value) {
571 Id id = ID_NULL;
572
573 Pool* pool = pakfire_get_solv_pool(pkg->pakfire);
574 Solvable* s = get_solvable(pkg);
575
576 const char* basename = NULL;
577 const char* dirname = NULL;
578
579 switch (key) {
580 // Do not allow to change name, evr, or arch
581 case PAKFIRE_PKG_NAME:
582 // Reset nevra & filename
583 *pkg->nevra = *pkg->filename = '\0';
584
585 s->name = pool_str2id(pool, value, 1);
586 return 0;
587
588 case PAKFIRE_PKG_EVR:
589 // Reset nevra & filename
590 *pkg->nevra = *pkg->filename = '\0';
591
592 // Skip empty epoch
593 if (pakfire_string_startswith(value, "0:"))
594 value += 2;
595
596 s->evr = pool_str2id(pool, value, 1);
597 return 0;
598
599 case PAKFIRE_PKG_ARCH:
600 // Reset nevra & filename
601 *pkg->nevra = *pkg->filename = '\0';
602
603 s->arch = pool_str2id(pool, value, 1);
604 return 0;
605
606 case PAKFIRE_PKG_NEVRA:
607 errno = EINVAL;
608 return 1;
609
610 case PAKFIRE_PKG_UUID:
611 id = SOLVABLE_PKGID;
612 break;
613
614 case PAKFIRE_PKG_SUMMARY:
615 id = SOLVABLE_SUMMARY;
616 break;
617
618 case PAKFIRE_PKG_DESCRIPTION:
619 id = SOLVABLE_DESCRIPTION;
620 break;
621
622 case PAKFIRE_PKG_LICENSE:
623 id = SOLVABLE_LICENSE;
624 break;
625
626 case PAKFIRE_PKG_URL:
627 id = SOLVABLE_URL;
628 break;
629
630 case PAKFIRE_PKG_GROUPS:
631 id = SOLVABLE_GROUP;
632 break;
633
634 case PAKFIRE_PKG_VENDOR:
635 id = SOLVABLE_VENDOR;
636 break;
637
638 case PAKFIRE_PKG_DISTRO:
639 id = SOLVABLE_DISTRIBUTION;
640 break;
641
642 case PAKFIRE_PKG_PACKAGER:
643 id = SOLVABLE_PACKAGER;
644 break;
645
646 case PAKFIRE_PKG_PATH:
647 if (value) {
648 basename = pakfire_basename(value);
649 dirname = pakfire_dirname(value);
650 }
651
652 if (basename)
653 solvable_set_str(s, SOLVABLE_MEDIAFILE, basename);
654 else
655 solvable_unset(s, SOLVABLE_MEDIAFILE);
656
657 if (dirname)
658 solvable_set_str(s, SOLVABLE_MEDIABASE, dirname);
659 else
660 solvable_unset(s, SOLVABLE_MEDIABASE);
661
662 // Cache the path
663 pakfire_string_set(pkg->path, value);
664
665 // Mark the package as changed
666 pakfire_package_has_changed(pkg);
667
668 return 0;
669
670 case PAKFIRE_PKG_FILENAME:
671 id = SOLVABLE_MEDIAFILE;
672 break;
673
674 case PAKFIRE_PKG_BUILD_HOST:
675 id = SOLVABLE_BUILDHOST;
676 break;
677
678 case PAKFIRE_PKG_BUILD_ID:
679 id = SOLVABLE_BUILDVERSION;
680 break;
681
682 case PAKFIRE_PKG_SOURCE_PKG:
683 // The source package name cannot be set
684 break;
685
686 case PAKFIRE_PKG_SOURCE_NAME:
687 id = SOLVABLE_SOURCENAME;
688 break;
689
690 case PAKFIRE_PKG_SOURCE_EVR:
691 // Skip empty epoch
692 if (pakfire_string_startswith(value, "0:"))
693 value += 2;
694
695 id = SOLVABLE_SOURCEEVR;
696 break;
697
698 case PAKFIRE_PKG_SOURCE_ARCH:
699 id = SOLVABLE_SOURCEARCH;
700 break;
701
702 default:
703 break;
704 }
705
706 // Check if we have found a valid ID
707 if (id == ID_NULL) {
708 errno = EINVAL;
709 return 1;
710 }
711
712 // Unset on empty string
713 if (!value)
714 solvable_unset(s, id);
715
716 // Store string
717 else
718 solvable_set_str(s, id, value);
719
720 // Mark the package as changed
721 pakfire_package_has_changed(pkg);
722
723 return 0;
724 }
725
726 PAKFIRE_EXPORT int pakfire_package_get_uuid(struct pakfire_package* pkg,
727 const enum pakfire_package_key key, uuid_t uuid) {
728 const char* buffer = NULL;
729 int r;
730
731 switch (key) {
732 case PAKFIRE_PKG_UUID:
733 case PAKFIRE_PKG_BUILD_ID:
734 // Clear the UUID
735 uuid_clear(uuid);
736
737 // Fetch the value
738 buffer = pakfire_package_get_string(pkg, key);
739 if (!buffer)
740 return 1;
741
742 // Read buffer into the output
743 r = uuid_parse(buffer, uuid);
744 if (r)
745 return r;
746
747 return 0;
748
749 default:
750 errno = EINVAL;
751 return 1;
752 }
753 }
754
755 PAKFIRE_EXPORT int pakfire_package_set_uuid(struct pakfire_package* pkg,
756 const enum pakfire_package_key key, const uuid_t uuid) {
757 char buffer[UUID_STR_LEN];
758
759 switch (key) {
760 case PAKFIRE_PKG_UUID:
761 case PAKFIRE_PKG_BUILD_ID:
762 // Convert the UUID to string
763 uuid_unparse_lower(uuid, buffer);
764
765 // Store the UUID as string
766 return pakfire_package_set_string(pkg, key, buffer);
767
768 default:
769 errno = EINVAL;
770 return 1;
771 }
772 }
773
774 PAKFIRE_EXPORT unsigned long long pakfire_package_get_num(struct pakfire_package* pkg,
775 const enum pakfire_package_key key, unsigned long long notfound) {
776 Id id = ID_NULL;
777
778 switch (key) {
779 case PAKFIRE_PKG_DBID:
780 id = RPM_RPMDBID;
781 break;
782
783 case PAKFIRE_PKG_DOWNLOADSIZE:
784 id = SOLVABLE_DOWNLOADSIZE;
785 break;
786
787 case PAKFIRE_PKG_INSTALLSIZE:
788 id = SOLVABLE_INSTALLSIZE;
789 break;
790
791 case PAKFIRE_PKG_BUILD_TIME:
792 id = SOLVABLE_BUILDTIME;
793 break;
794
795 case PAKFIRE_PKG_INSTALLTIME:
796 id = SOLVABLE_INSTALLTIME;
797 break;
798
799 // Return zero for all unhandled keys
800 default:
801 errno = EINVAL;
802 return 1;
803 }
804
805 Solvable* s = get_solvable(pkg);
806
807 pakfire_package_internalize_repo(pkg);
808
809 return solvable_lookup_num(s, id, notfound);
810 }
811
812 PAKFIRE_EXPORT int pakfire_package_set_num(struct pakfire_package* pkg,
813 const enum pakfire_package_key key, unsigned long long num) {
814 Id id = ID_NULL;
815
816 switch (key) {
817 case PAKFIRE_PKG_DBID:
818 id = RPM_RPMDBID;
819 break;
820
821 case PAKFIRE_PKG_DOWNLOADSIZE:
822 id = SOLVABLE_DOWNLOADSIZE;
823 break;
824
825 case PAKFIRE_PKG_INSTALLSIZE:
826 id = SOLVABLE_INSTALLSIZE;
827 break;
828
829 case PAKFIRE_PKG_BUILD_TIME:
830 id = SOLVABLE_BUILDTIME;
831 break;
832
833 case PAKFIRE_PKG_INSTALLTIME:
834 id = SOLVABLE_INSTALLTIME;
835 break;
836
837 // Return zero for all unhandled keys
838 default:
839 errno = EINVAL;
840 return 1;
841 }
842
843 Solvable* s = get_solvable(pkg);
844
845 // Store the number
846 solvable_set_num(s, id, num);
847
848 // Mark the package as changed
849 pakfire_package_has_changed(pkg);
850
851 return 0;
852 }
853
854 static enum pakfire_digest_types pakfire_package_id2digest(Id id) {
855 switch (id) {
856 case REPOKEY_TYPE_SHA512:
857 return PAKFIRE_DIGEST_SHA2_512;
858
859 case REPOKEY_TYPE_SHA256:
860 return PAKFIRE_DIGEST_SHA2_256;
861 }
862
863 return 0;
864 }
865
866 PAKFIRE_EXPORT const unsigned char* pakfire_package_get_digest(
867 struct pakfire_package* pkg, enum pakfire_digest_types* type, size_t* length) {
868 Solvable* s = get_solvable(pkg);
869 Id id = 0;
870
871 const unsigned char* checksum = solvable_lookup_bin_checksum(s, SOLVABLE_CHECKSUM, &id);
872
873 // Convert ID to digest type
874 *type = pakfire_package_id2digest(id);
875 if (!*type) {
876 errno = ENOTSUP;
877 checksum = NULL;
878 }
879
880 // Store the length (if requested)
881 if (length)
882 *length = pakfire_digest_length(*type);
883
884 return checksum;
885 }
886
887 PAKFIRE_EXPORT int pakfire_package_set_digest(struct pakfire_package* pkg,
888 enum pakfire_digest_types type, const unsigned char* digest, const size_t length) {
889 Solvable* s = get_solvable(pkg);
890 Pool* pool = s->repo->pool;
891 Id id;
892 int r = 1;
893
894 switch (type) {
895 case PAKFIRE_DIGEST_SHA2_256:
896 id = REPOKEY_TYPE_SHA256;
897 break;
898
899 case PAKFIRE_DIGEST_SHA2_512:
900 id = REPOKEY_TYPE_SHA512;
901 break;
902
903 default:
904 errno = ENOTSUP;
905 return 1;
906 }
907
908 // Check if the digest length matches
909 if (pakfire_digest_length(type) != length) {
910 errno = EINVAL;
911 return 1;
912 }
913
914 struct pakfire_repo* repo = pakfire_package_get_repo(pkg);
915
916 Repodata* data = pakfire_repo_get_repodata(repo);
917 if (!data)
918 goto ERROR;
919
920 repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, id, digest);
921
922 // Success
923 r = 0;
924
925 ERROR:
926 pakfire_repo_unref(repo);
927
928 return r;
929 }
930
931 int pakfire_package_is_installed(struct pakfire_package* pkg) {
932 Pool* pool = pakfire_get_solv_pool(pkg->pakfire);
933 Solvable* s = get_solvable(pkg);
934
935 return pool->installed == s->repo;
936 }
937
938 PAKFIRE_EXPORT size_t pakfire_package_get_size(struct pakfire_package* pkg) {
939 if (pakfire_package_is_installed(pkg))
940 return pakfire_package_get_num(pkg, PAKFIRE_PKG_INSTALLSIZE, 0);
941
942 return pakfire_package_get_num(pkg, PAKFIRE_PKG_DOWNLOADSIZE, 0);
943 }
944
945 // Dependencies
946
947 PAKFIRE_EXPORT char** pakfire_package_get_deps(struct pakfire_package* pkg,
948 const enum pakfire_package_key key) {
949 Solvable* s = get_solvable(pkg);
950 char** ret = NULL;
951 int r;
952
953 Queue q;
954 Id id = ID_NULL;
955 Id marker = ID_NULL;
956 const char* dep = NULL;
957
958 r = pakfire_package_dep2id(key, &id, &marker);
959 if (r)
960 return NULL;
961
962 // Initialize the output queue
963 queue_init(&q);
964
965 // Fetch all deps
966 solvable_lookup_deparray(s, id, &q, marker);
967
968 // Allocate array
969 ret = calloc(q.count + 1, sizeof(*ret));
970 if (!ret)
971 goto ERROR;
972
973 for (int i = 0; i < q.count; i++) {
974 dep = pakfire_dep2str(pkg->pakfire, q.elements[i]);
975 if (!dep)
976 goto ERROR;
977
978 ret[i] = strdup(dep);
979 if (!ret[i])
980 goto ERROR;
981 }
982
983 // All good!
984 goto SUCCESS;
985
986 ERROR:
987 if (ret) {
988 for (char** e = ret; *e; e++)
989 free(*e);
990 free(ret);
991
992 ret = NULL;
993 }
994
995 SUCCESS:
996 queue_free(&q);
997
998 return ret;
999 }
1000
1001 int pakfire_package_add_dep(struct pakfire_package* pkg,
1002 const enum pakfire_package_key key, const char* dep) {
1003 // Parse the dependency
1004 Id id = pakfire_str2dep(pkg->pakfire, dep);
1005
1006 // Silently ignore any invalid dependencies
1007 if (!id)
1008 return 0;
1009
1010 return pakfire_package_add_depid(pkg, key, id);
1011 }
1012
1013 PAKFIRE_EXPORT int pakfire_package_get_reverse_requires(struct pakfire_package* pkg,
1014 struct pakfire_packagelist* list) {
1015 Queue matches;
1016 queue_init(&matches);
1017
1018 // Get the pool ready
1019 pakfire_pool_internalize(pkg->pakfire);
1020
1021 Pool* pool = pakfire_get_solv_pool(pkg->pakfire);
1022
1023 // Search for any matches
1024 pool_whatmatchessolvable(pool, SOLVABLE_REQUIRES, pkg->id, &matches, 0);
1025
1026 // Import the result to the package list
1027 int r = pakfire_packagelist_import_solvables(list, &matches);
1028 if (r)
1029 goto ERROR;
1030
1031 ERROR:
1032 queue_free(&matches);
1033
1034 return r;
1035 }
1036
1037 static int pakfire_package_has_rich_deps_in_deparray(
1038 struct pakfire_package* pkg, Id type) {
1039 int r = 0;
1040
1041 Solvable* s = get_solvable(pkg);
1042
1043 Queue q;
1044 queue_init(&q);
1045
1046 // Fetch all deps
1047 solvable_lookup_deparray(s, type, &q, 0);
1048
1049 // Nothing to do if the array was empty
1050 if (!q.count)
1051 goto ERROR;
1052
1053 for (int i = 0; i < q.count; i++) {
1054 const char* dep = pakfire_dep2str(pkg->pakfire, q.elements[i]);
1055
1056 // Is this a rich dependency?
1057 if (dep && *dep == '(') {
1058 r = 1;
1059 break;
1060 }
1061 }
1062
1063 ERROR:
1064 queue_free(&q);
1065
1066 return r;
1067 }
1068
1069 int pakfire_package_has_rich_deps(struct pakfire_package* pkg) {
1070 const Id types[] = {
1071 // Requires (includes pre-requires)
1072 SOLVABLE_REQUIRES,
1073 SOLVABLE_PROVIDES,
1074 SOLVABLE_CONFLICTS,
1075 SOLVABLE_OBSOLETES,
1076 SOLVABLE_RECOMMENDS,
1077 SOLVABLE_SUGGESTS,
1078 SOLVABLE_SUPPLEMENTS,
1079 SOLVABLE_ENHANCES,
1080 0,
1081 };
1082
1083 for (const Id* type = types; *type; type++) {
1084 int r = pakfire_package_has_rich_deps_in_deparray(pkg, *type);
1085 if (r)
1086 return r;
1087 }
1088
1089 // No match
1090 return 0;
1091 }
1092
1093 int pakfire_package_matches_dep(struct pakfire_package* pkg,
1094 const enum pakfire_package_key key, const char* dep) {
1095 int r;
1096
1097 Id id = ID_NULL;
1098 int marker = 0;
1099
1100 // Translate the dependency type
1101 r = pakfire_package_dep2id(key, &id, &marker);
1102 if (r)
1103 return r;
1104
1105 // Get the dependency
1106 Id depid = pakfire_str2dep(pkg->pakfire, dep);
1107 if (!depid)
1108 return 0;
1109
1110 // Fetch the solvable
1111 Solvable* s = get_solvable(pkg);
1112
1113 // Check whether this solvable matches the requested dependency
1114 return solvable_matchesdep(s, id, depid, marker);
1115 }
1116
1117 PAKFIRE_EXPORT struct pakfire_repo* pakfire_package_get_repo(struct pakfire_package* pkg) {
1118 if (!pkg->repo) {
1119 Solvable* s = get_solvable(pkg);
1120
1121 pkg->repo = pakfire_repo_create_from_repo(pkg->pakfire, s->repo);
1122 }
1123
1124 return pakfire_repo_ref(pkg->repo);
1125 }
1126
1127 static void pakfire_package_dump_add_line(char** str, const char* key, const char* val) {
1128 if (val)
1129 asprintf(str, "%s%-15s: %s\n", *str, key ? key : "", val);
1130 }
1131
1132 static void pakfire_package_dump_add_lines(char** str, const char* key, const char* val) {
1133 char** lines = pakfire_string_split(val, '\n');
1134 if (!lines)
1135 return;
1136
1137 while (*lines) {
1138 pakfire_package_dump_add_line(str, key, *lines);
1139 lines++;
1140 }
1141 }
1142
1143 static void pakfire_package_dump_add_line_date(char** str, const char* key, time_t date) {
1144 char buffer[1024];
1145 int r;
1146
1147 // Format time
1148 r = pakfire_strftime(buffer, "%a, %d %b %Y %T %z", date);
1149 if (r)
1150 return;
1151
1152 pakfire_package_dump_add_line(str, key, buffer);
1153 }
1154
1155 static void pakfire_package_dump_add_line_hex(char** str,
1156 const char* key, const unsigned char* buffer, const size_t length) {
1157 char* hex = __pakfire_hexlify(buffer, length);
1158 if (!hex)
1159 return;
1160
1161 pakfire_package_dump_add_line(str, key, hex);
1162 free(hex);
1163 }
1164
1165 static void pakfire_package_dump_add_line_size(char** str, const char* key, size_t size) {
1166 char buffer[128];
1167
1168 // Format size in human-readable format
1169 int r = pakfire_format_size(buffer, size);
1170 if (r < 0)
1171 return;
1172
1173 pakfire_package_dump_add_line(str, key, buffer);
1174 }
1175
1176 static int pakfire_sort_dependencies(const void* p1, const void* p2) {
1177 const char* dep1 = *(const char**)p1;
1178 const char* dep2 = *(const char**)p2;
1179
1180 return strcmp(dep1, dep2);
1181 }
1182
1183 PAKFIRE_EXPORT char* pakfire_package_dump(struct pakfire_package* pkg, int flags) {
1184 char* string = "";
1185
1186 // Name
1187 const char* name = pakfire_package_get_string(pkg, PAKFIRE_PKG_NAME);
1188 if (name)
1189 pakfire_package_dump_add_line(&string, _("Name"), name);
1190
1191 // EVR
1192 const char* evr = pakfire_package_get_string(pkg, PAKFIRE_PKG_EVR);
1193 if (evr)
1194 pakfire_package_dump_add_line(&string, _("Version"), evr);
1195
1196 // Arch
1197 const char* arch = pakfire_package_get_string(pkg, PAKFIRE_PKG_ARCH);
1198 if (arch)
1199 pakfire_package_dump_add_line(&string, _("Arch"), arch);
1200
1201 // Size
1202 size_t size = pakfire_package_get_size(pkg);
1203 if (size)
1204 pakfire_package_dump_add_line_size(&string, _("Size"), size);
1205
1206 // Installed Size
1207 if (pakfire_package_is_installed(pkg)) {
1208 size_t installsize = pakfire_package_get_num(pkg, PAKFIRE_PKG_INSTALLSIZE, 0);
1209 if (installsize)
1210 pakfire_package_dump_add_line_size(&string, _("Installed Size"), installsize);
1211
1212 // Download Size
1213 } else {
1214 size_t downloadsize = pakfire_package_get_num(pkg, PAKFIRE_PKG_DOWNLOADSIZE, 0);
1215 if (downloadsize)
1216 pakfire_package_dump_add_line_size(&string, _("Download Size"), downloadsize);
1217 }
1218
1219 // Repository
1220 struct pakfire_repo* repo = pakfire_package_get_repo(pkg);
1221 if (repo) {
1222 if (!pakfire_repo_name_equals(repo, PAKFIRE_REPO_DUMMY)) {
1223 const char* repo_name = pakfire_repo_get_name(repo);
1224 pakfire_package_dump_add_line(&string, _("Repo"), repo_name);
1225 }
1226
1227 pakfire_repo_unref(repo);
1228 }
1229
1230 // Summary
1231 const char* summary = pakfire_package_get_string(pkg, PAKFIRE_PKG_SUMMARY);
1232 if (summary)
1233 pakfire_package_dump_add_line(&string, _("Summary"), summary);
1234
1235 // Description
1236 const char* description = pakfire_package_get_string(pkg, PAKFIRE_PKG_DESCRIPTION);
1237 if (description)
1238 pakfire_package_dump_add_lines(&string, _("Description"), description);
1239
1240 // Groups
1241 const char* groups = pakfire_package_get_string(pkg, PAKFIRE_PKG_GROUPS);
1242 if (groups)
1243 pakfire_package_dump_add_lines(&string, _("Groups"), groups);
1244
1245 // URL
1246 const char* url = pakfire_package_get_string(pkg, PAKFIRE_PKG_URL);
1247 if (url)
1248 pakfire_package_dump_add_line(&string, _("URL"), url);
1249
1250 // License
1251 const char* license = pakfire_package_get_string(pkg, PAKFIRE_PKG_LICENSE);
1252 if (license)
1253 pakfire_package_dump_add_line(&string, _("License"), license);
1254
1255 if (flags & PAKFIRE_PKG_DUMP_LONG) {
1256 // Install Time
1257 time_t install_time = pakfire_package_get_num(pkg, PAKFIRE_PKG_INSTALLTIME, 0);
1258 if (install_time)
1259 pakfire_package_dump_add_line_date(&string, _("Install Time"), install_time);
1260
1261 // Distribution
1262 const char* distro = pakfire_package_get_string(pkg, PAKFIRE_PKG_DISTRO);
1263 if (distro)
1264 pakfire_package_dump_add_line(&string, _("Distribution"), distro);
1265
1266 // Packager
1267 const char* packager = pakfire_package_get_string(pkg, PAKFIRE_PKG_PACKAGER);
1268 if (packager)
1269 pakfire_package_dump_add_line(&string, _("Packager"), packager);
1270
1271 // Vendor
1272 const char* vendor = pakfire_package_get_string(pkg, PAKFIRE_PKG_VENDOR);
1273 if (vendor)
1274 pakfire_package_dump_add_line(&string, _("Vendor"), vendor);
1275
1276 // UUID
1277 const char* uuid = pakfire_package_get_string(pkg, PAKFIRE_PKG_UUID);
1278 if (uuid)
1279 pakfire_package_dump_add_line(&string, _("UUID"), uuid);
1280
1281 // Build ID
1282 const char* build_id = pakfire_package_get_string(pkg, PAKFIRE_PKG_BUILD_ID);
1283 if (build_id)
1284 pakfire_package_dump_add_line(&string, _("Build ID"), build_id);
1285
1286 enum pakfire_digest_types digest_type = PAKFIRE_DIGEST_UNDEFINED;
1287 size_t digest_length = 0;
1288
1289 // Digest
1290 const unsigned char* digest = pakfire_package_get_digest(pkg,
1291 &digest_type, &digest_length);
1292 if (digest) {
1293 switch (digest_type) {
1294 case PAKFIRE_DIGEST_SHA2_512:
1295 pakfire_package_dump_add_line_hex(&string,
1296 _("SHA2-512 Digest"), digest, digest_length);
1297 break;
1298
1299 case PAKFIRE_DIGEST_SHA2_256:
1300 pakfire_package_dump_add_line_hex(&string,
1301 _("SHA2-256 Digest"), digest, digest_length);
1302 break;
1303
1304 case PAKFIRE_DIGEST_SHA3_512:
1305 case PAKFIRE_DIGEST_SHA3_256:
1306 case PAKFIRE_DIGEST_BLAKE2B512:
1307 case PAKFIRE_DIGEST_BLAKE2S256:
1308 case PAKFIRE_DIGEST_UNDEFINED:
1309 break;
1310 }
1311 }
1312
1313 // Source package
1314 const char* source_package = pakfire_package_get_string(pkg, PAKFIRE_PKG_SOURCE_PKG);
1315 if (source_package)
1316 pakfire_package_dump_add_line(&string, _("Source Package"), source_package);
1317
1318 // Build time
1319 time_t build_time = pakfire_package_get_num(pkg, PAKFIRE_PKG_BUILD_TIME, 0);
1320 if (build_time)
1321 pakfire_package_dump_add_line_date(&string, _("Build Time"), build_time);
1322
1323 // Build host
1324 const char* build_host = pakfire_package_get_string(pkg, PAKFIRE_PKG_BUILD_HOST);
1325 if (build_host)
1326 pakfire_package_dump_add_line(&string, _("Build Host"), build_host);
1327
1328 // Dependencies
1329 for (const struct pakfire_dep* dep = pakfire_deps; dep->key; dep++) {
1330 char** deps = pakfire_package_get_deps(pkg, dep->key);
1331 if (deps) {
1332 size_t count = 0;
1333
1334 // Count elements in the list
1335 for (char** d = deps; *d; d++)
1336 count++;
1337
1338 // Sort the list
1339 qsort(deps, count, sizeof(*deps), pakfire_sort_dependencies);
1340
1341 switch (dep->key) {
1342 case PAKFIRE_PKG_PROVIDES:
1343 name = _("Provides");
1344 break;
1345
1346 case PAKFIRE_PKG_PREREQUIRES:
1347 name = _("Pre-Requires");
1348 break;
1349
1350 case PAKFIRE_PKG_REQUIRES:
1351 name = _("Requires");
1352 break;
1353
1354 case PAKFIRE_PKG_CONFLICTS:
1355 name = _("Conflicts");
1356 break;
1357
1358 case PAKFIRE_PKG_OBSOLETES:
1359 name = _("Obsoletes");
1360 break;
1361
1362 case PAKFIRE_PKG_RECOMMENDS:
1363 name = _("Recommends");
1364 break;
1365
1366 case PAKFIRE_PKG_SUGGESTS:
1367 name = _("Suggests");
1368 break;
1369
1370 case PAKFIRE_PKG_SUPPLEMENTS:
1371 name = _("Supplements");
1372 break;
1373
1374 case PAKFIRE_PKG_ENHANCES:
1375 name = _("Enhances");
1376 break;
1377
1378 default:
1379 name = NULL;
1380 break;
1381 }
1382
1383 // Write it to the console
1384 for (char** d = deps; *d; d++) {
1385 pakfire_package_dump_add_line(&string, name, *d);
1386 free(*d);
1387
1388 // Clear name after first line
1389 name = NULL;
1390 }
1391 free(deps);
1392 }
1393 }
1394 }
1395
1396 if (flags & PAKFIRE_PKG_DUMP_FILELIST) {
1397 struct pakfire_filelist* filelist = pakfire_package_get_filelist(pkg);
1398
1399 const char* prefix = _("Filelist");
1400
1401 for (unsigned int i = 0; i < pakfire_filelist_length(filelist); i++) {
1402 struct pakfire_file* file = pakfire_filelist_get(filelist, i);
1403
1404 const char* path = pakfire_file_get_path(file);
1405 pakfire_package_dump_add_line(&string, prefix, path);
1406
1407 pakfire_file_unref(file);
1408
1409 // Only prefix the first line
1410 prefix = NULL;
1411 }
1412
1413 pakfire_filelist_unref(filelist);
1414 }
1415
1416 return string;
1417 }
1418
1419 PAKFIRE_EXPORT struct pakfire_archive* pakfire_package_get_archive(struct pakfire_package* pkg) {
1420 struct pakfire_archive* archive = NULL;
1421
1422 // Otherwise open the archive from the cache
1423 const char* path = pakfire_package_get_string(pkg, PAKFIRE_PKG_PATH);
1424 if (!path)
1425 return NULL;
1426
1427 // Open archive
1428 int r = pakfire_archive_open(&archive, pkg->pakfire, path);
1429 if (r)
1430 return NULL;
1431
1432 return archive;
1433 }
1434
1435 struct pakfire_package_filelist_search {
1436 struct pakfire* pakfire;
1437 struct pakfire_filelist* filelist;
1438 int r;
1439 };
1440
1441 static int __pakfire_package_fetch_filelist(void* data, Solvable* s, Repodata* repodata,
1442 Repokey* key, struct s_KeyValue* kv) {
1443 struct pakfire_package_filelist_search* search = (struct pakfire_package_filelist_search*)data;
1444
1445 struct pakfire_file* file = NULL;
1446 int r;
1447
1448 // Skip any results of the wrong type
1449 if (key->type != REPOKEY_TYPE_DIRSTRARRAY)
1450 return 0;
1451
1452 // Fetch the path
1453 const char* path = repodata_dir2str(repodata, kv->id, kv->str);
1454 if (!path) {
1455 r = 1;
1456 goto ERROR;
1457 }
1458
1459 // Create a new file entry
1460 r = pakfire_file_create(&file, search->pakfire);
1461 if (r)
1462 goto ERROR;
1463
1464 // Set path
1465 r = pakfire_file_set_path(file, path);
1466 if (r)
1467 goto ERROR;
1468
1469 // Append the file to the filelist
1470 r = pakfire_filelist_add(search->filelist, file);
1471 if (r)
1472 goto ERROR;
1473
1474 ERROR:
1475 // Store the error code
1476 search->r = r;
1477
1478 if (file)
1479 pakfire_file_unref(file);
1480
1481 return r;
1482 }
1483
1484 static int pakfire_package_fetch_filelist(struct pakfire_package* pkg, struct pakfire_filelist* filelist) {
1485 struct pakfire_package_filelist_search search = {
1486 .pakfire = pkg->pakfire,
1487 .filelist = filelist,
1488 .r = 0,
1489 };
1490
1491 pakfire_package_internalize_repo(pkg);
1492
1493 Solvable* s = get_solvable(pkg);
1494
1495 Repodata* repodata = repo_last_repodata(s->repo);
1496
1497 // Search for all files
1498 repodata_search(repodata, pkg->id, SOLVABLE_FILELIST, SEARCH_FILES,
1499 __pakfire_package_fetch_filelist, &search);
1500
1501 // Break on any error
1502 if (search.r)
1503 return search.r;
1504
1505 return search.r;
1506 }
1507
1508 PAKFIRE_EXPORT struct pakfire_filelist* pakfire_package_get_filelist(struct pakfire_package* pkg) {
1509 struct pakfire_filelist* filelist = NULL;
1510
1511 // Create a new filelist
1512 int r = pakfire_filelist_create(&filelist, pkg->pakfire);
1513 if (r)
1514 goto ERROR;
1515
1516 // Fetch all entries from the repository database
1517 r = pakfire_package_fetch_filelist(pkg, filelist);
1518 if (r)
1519 goto ERROR;
1520
1521 return filelist;
1522
1523 ERROR:
1524 if (filelist)
1525 pakfire_filelist_unref(filelist);
1526
1527 return NULL;
1528 }
1529
1530 int pakfire_package_append_file(struct pakfire_package* pkg, const char* path) {
1531 // Fetch repodata
1532 struct pakfire_repo* repo = pakfire_package_get_repo(pkg);
1533 if (!repo) {
1534 ERROR(pkg->pakfire, "Could not find repository for %s: %m\n",
1535 pakfire_package_get_string(pkg, PAKFIRE_PKG_NEVRA));
1536 return 1;
1537 }
1538
1539 Repodata* repodata = pakfire_repo_get_repodata(repo);
1540
1541 const char* basename = pakfire_basename(path);
1542 const char* dirname = pakfire_dirname(path);
1543
1544 // Convert directory into ID
1545 Id did = repodata_str2dir(repodata, dirname, 1);
1546 if (!did)
1547 did = repodata_str2dir(repodata, "/", 1);
1548
1549 // Add data to list
1550 repodata_add_dirstr(repodata, pkg->id,
1551 SOLVABLE_FILELIST, did, basename);
1552
1553 pakfire_repo_unref(repo);
1554
1555 // This package has changed
1556 pakfire_package_has_changed(pkg);
1557
1558 return 0;
1559 }
1560
1561 static int __pakfire_package_set_filelist(struct pakfire* pakfire,
1562 struct pakfire_file* file, void* data) {
1563 struct pakfire_package* pkg = (struct pakfire_package*)data;
1564
1565 // Fetch the path
1566 const char* path = pakfire_file_get_path(file);
1567
1568 return pakfire_package_append_file(pkg, path);
1569 }
1570
1571 PAKFIRE_EXPORT int pakfire_package_set_filelist(
1572 struct pakfire_package* pkg, struct pakfire_filelist* filelist) {
1573 return pakfire_filelist_walk(filelist, __pakfire_package_set_filelist, pkg, 0);
1574 }
1575
1576 int pakfire_package_set_filelist_from_string(struct pakfire_package* pkg, const char* files) {
1577 char* p = NULL;
1578 int r = 0;
1579
1580 // Copy files
1581 char* buffer = strdup(files);
1582 if (!buffer)
1583 goto ERROR;
1584
1585 // Walk through all files
1586 char* path = strtok_r(buffer, "\n", &p);
1587 while (path) {
1588 r = pakfire_package_append_file(pkg, path);
1589 if (r)
1590 goto ERROR;
1591
1592 path = strtok_r(NULL, "\n", &p);
1593 }
1594
1595 ERROR:
1596 if (buffer)
1597 free(buffer);
1598
1599 return r;
1600 }
1601
1602 static int _pakfire_package_add_json_dependencies(
1603 struct pakfire_package* pkg,
1604 struct json_object* json,
1605 const char* name,
1606 const enum pakfire_package_key key) {
1607 // Fetch dependencies
1608 char** dependencies = pakfire_package_get_deps(pkg, key);
1609 if (!dependencies)
1610 return 1;
1611
1612 // Add dependencies
1613 int r = pakfire_json_add_string_array(pkg->pakfire, json, name, dependencies);
1614 if (r)
1615 goto ERROR;
1616
1617 ERROR:
1618 if (dependencies) {
1619 for (char** dep = dependencies; *dep; dep++)
1620 free(*dep);
1621 free(dependencies);
1622 }
1623
1624 return r;
1625 }
1626
1627 static int pakfire_package_add_json_dependencies(
1628 struct pakfire_package* pkg, struct json_object* md) {
1629 int r = 0;
1630
1631 // Create new dependencies object
1632 struct json_object* object = json_object_new_object();
1633 if (!object)
1634 return 1;
1635
1636 // Pre-requires
1637 r = _pakfire_package_add_json_dependencies(pkg, object,
1638 "prerequires", PAKFIRE_PKG_PREREQUIRES);
1639 if (r)
1640 goto ERROR;
1641
1642 // Requires
1643 r = _pakfire_package_add_json_dependencies(pkg, object,
1644 "requires", PAKFIRE_PKG_REQUIRES);
1645 if (r)
1646 goto ERROR;
1647
1648 // Provides
1649 r = _pakfire_package_add_json_dependencies(pkg, object,
1650 "provides", PAKFIRE_PKG_PROVIDES);
1651 if (r)
1652 goto ERROR;
1653
1654 // Conflicts
1655 r = _pakfire_package_add_json_dependencies(pkg, object,
1656 "conflicts", PAKFIRE_PKG_CONFLICTS);
1657 if (r)
1658 goto ERROR;
1659
1660 // Obsoletes
1661 r = _pakfire_package_add_json_dependencies(pkg, object,
1662 "obsoletes", PAKFIRE_PKG_OBSOLETES);
1663 if (r)
1664 goto ERROR;
1665
1666 // Recommends
1667 r = _pakfire_package_add_json_dependencies(pkg, object,
1668 "recommends", PAKFIRE_PKG_RECOMMENDS);
1669 if (r)
1670 goto ERROR;
1671
1672 // Suggests
1673 r = _pakfire_package_add_json_dependencies(pkg, object,
1674 "suggests", PAKFIRE_PKG_SUGGESTS);
1675 if (r)
1676 goto ERROR;
1677
1678 // Supplements
1679 r = _pakfire_package_add_json_dependencies(pkg, object,
1680 "supplements", PAKFIRE_PKG_SUPPLEMENTS);
1681 if (r)
1682 goto ERROR;
1683
1684 // Enhances
1685 r = _pakfire_package_add_json_dependencies(pkg, object,
1686 "enhances", PAKFIRE_PKG_ENHANCES);
1687 if (r)
1688 goto ERROR;
1689
1690 // Add object
1691 r = json_object_object_add(md, "dependencies", object);
1692 if (r)
1693 goto ERROR;
1694
1695 ERROR:
1696 if (r)
1697 json_object_put(object);
1698
1699 return r;
1700 }
1701
1702 static int __pakfire_package_add_json_filelist(struct pakfire* pakfire,
1703 struct pakfire_file* file, void* data) {
1704 struct json_object* filelist = (struct json_object*)data;
1705 int r = 1;
1706
1707 // Fetch the file path
1708 const char* path = pakfire_file_get_path(file);
1709
1710 // Create a new JSON string
1711 struct json_object* object = json_object_new_string(path);
1712 if (!object)
1713 goto ERROR;
1714
1715 // Append the string
1716 r = json_object_array_add(filelist, object);
1717 if (r)
1718 goto ERROR;
1719
1720 return 0;
1721
1722 ERROR:
1723 // Free JSON string
1724 if (object)
1725 json_object_put(object);
1726
1727 return r;
1728 }
1729
1730 static int pakfire_package_add_json_filelist(
1731 struct pakfire_package* pkg, struct json_object* md) {
1732 struct pakfire_filelist* filelist = NULL;
1733 struct json_object* object = NULL;
1734 int r;
1735
1736 // Fetch the filelist
1737 filelist = pakfire_package_get_filelist(pkg);
1738 if (!filelist) {
1739 ERROR(pkg->pakfire, "Could not fetch package filelist\n");
1740 r = 1;
1741 goto ERROR;
1742 }
1743
1744 // Create a new JSON array
1745 object = json_object_new_array();
1746 if (!object) {
1747 ERROR(pkg->pakfire, "Could not create a JSON array\n");
1748 r = 1;
1749 goto ERROR;
1750 }
1751
1752 // Walk through the filelist
1753 r = pakfire_filelist_walk(filelist, __pakfire_package_add_json_filelist, object, 0);
1754 if (r)
1755 goto ERROR;
1756
1757 // Add object
1758 r = json_object_object_add(md, "filelist", object);
1759 if (r)
1760 goto ERROR;
1761
1762 ERROR:
1763 // Free JSON object on error
1764 if (r)
1765 json_object_put(object);
1766 if (filelist)
1767 pakfire_filelist_unref(filelist);
1768
1769 return r;
1770 }
1771
1772 static int __pakfire_package_add_build_packages(struct pakfire* pakfire,
1773 struct pakfire_package* pkg, void* p) {
1774 struct json_object* object = (struct json_object*)p;
1775 int r;
1776
1777 const char* name = pakfire_package_get_string(pkg, PAKFIRE_PKG_NAME);
1778 const char* evr = pakfire_package_get_string(pkg, PAKFIRE_PKG_EVR);
1779
1780 if (!name || !evr) {
1781 ERROR(pakfire, "Could not fetch package information: %m\n");
1782 return 1;
1783 }
1784
1785 // Add package information to the list
1786 r = pakfire_json_add_string(pakfire, object, name, evr);
1787 if (r) {
1788 ERROR(pakfire, "Could not add package to packages list: %m\n");
1789 return r;
1790 }
1791
1792 return 0;
1793 }
1794
1795 static int pakfire_package_add_build_packages(struct pakfire_package* pkg,
1796 struct json_object* md) {
1797 struct pakfire_repo* repo = NULL;
1798 struct pakfire_packagelist* packages = NULL;
1799 struct json_object* object = NULL;
1800 int r;
1801
1802 // Create a new JSON array
1803 object = json_object_new_object();
1804 if (!object) {
1805 ERROR(pkg->pakfire, "Could not create a new JSON object: %m\n");
1806 r = 1;
1807 goto ERROR;
1808 }
1809
1810 // Fetch the installed repository
1811 repo = pakfire_get_installed_repo(pkg->pakfire);
1812 if (!repo) {
1813 ERROR(pkg->pakfire, "Could not fetch the installed repository: %m\n");
1814 r = 1;
1815 goto ERROR;
1816 }
1817
1818 // Create a new list
1819 r = pakfire_packagelist_create(&packages, pkg->pakfire);
1820 if (r)
1821 goto ERROR;
1822
1823 // Fetch all installed packages
1824 r = pakfire_repo_to_packagelist(repo, packages);
1825 if (r) {
1826 ERROR(pkg->pakfire, "Could not fetch packages from installed repository: %m\n");
1827 goto ERROR;
1828 }
1829
1830 // Add all packages to the array
1831 r = pakfire_packagelist_walk(packages, __pakfire_package_add_build_packages, object);
1832 if (r)
1833 goto ERROR;
1834
1835 // Add object
1836 r = json_object_object_add(md, "packages", json_object_get(object));
1837 if (r)
1838 goto ERROR;
1839
1840 ERROR:
1841 if (packages)
1842 pakfire_packagelist_unref(packages);
1843 if (repo)
1844 pakfire_repo_unref(repo);
1845 if (object)
1846 json_object_put(object);
1847
1848 return r;
1849 }
1850
1851 static int pakfire_package_add_build_metadata(struct pakfire_package* pkg,
1852 struct json_object* md) {
1853 int r;
1854
1855 // Create a new JSON object
1856 struct json_object* object = json_object_new_object();
1857 if (!object)
1858 return 1;
1859
1860 // Add pakfire version that generated this metadata
1861 r = pakfire_json_add_string(pkg->pakfire, object, "pakfire", PACKAGE_VERSION);
1862 if (r)
1863 goto ERROR;
1864
1865 // Write build host
1866 const char* build_host = pakfire_package_get_string(pkg, PAKFIRE_PKG_BUILD_HOST);
1867 if (build_host) {
1868 r = pakfire_json_add_string(pkg->pakfire, object, "host", build_host);
1869 if (r)
1870 goto ERROR;
1871 }
1872
1873 // Write build id
1874 const char* build_id = pakfire_package_get_string(pkg, PAKFIRE_PKG_BUILD_ID);
1875 if (build_id) {
1876 r = pakfire_json_add_string(pkg->pakfire, object, "id", build_id);
1877 if (r)
1878 goto ERROR;
1879 }
1880
1881 // Write build host
1882 time_t build_time = pakfire_package_get_num(pkg, PAKFIRE_PKG_BUILD_TIME, 0);
1883 if (build_time) {
1884 r = pakfire_json_add_integer(pkg->pakfire, object, "time", build_time);
1885 if (r)
1886 goto ERROR;
1887 }
1888
1889 // Source package name
1890 const char* name = pakfire_package_get_string(pkg, PAKFIRE_PKG_SOURCE_NAME);
1891 if (name) {
1892 r = pakfire_json_add_string(pkg->pakfire, object, "source-name", name);
1893 if (r)
1894 goto ERROR;
1895 }
1896
1897 // Source package EVR
1898 const char* evr = pakfire_package_get_string(pkg, PAKFIRE_PKG_SOURCE_EVR);
1899 if (evr) {
1900 r = pakfire_json_add_string(pkg->pakfire, object, "source-evr", evr);
1901 if (r)
1902 goto ERROR;
1903 }
1904
1905 // Source package arch
1906 const char* arch = pakfire_package_get_string(pkg, PAKFIRE_PKG_SOURCE_ARCH);
1907 if (arch) {
1908 r = pakfire_json_add_string(pkg->pakfire, object, "source-arch", arch);
1909 if (r)
1910 goto ERROR;
1911 }
1912
1913 // Build Packages
1914 if (!pakfire_package_is_source(pkg)) {
1915 r = pakfire_package_add_build_packages(pkg, object);
1916 if (r)
1917 goto ERROR;
1918 }
1919
1920 // Add object
1921 r = json_object_object_add(md, "build", object);
1922 if (r)
1923 goto ERROR;
1924
1925 ERROR:
1926 if (r)
1927 json_object_put(object);
1928
1929 return r;
1930 }
1931
1932 struct json_object* pakfire_package_to_json(struct pakfire_package* pkg) {
1933 struct json_object* md = json_object_new_object();
1934 int r = 0;
1935
1936 // Name
1937 const char* name = pakfire_package_get_string(pkg, PAKFIRE_PKG_NAME);
1938 if (name) {
1939 r = pakfire_json_add_string(pkg->pakfire, md, "name", name);
1940 if (r)
1941 goto ERROR;
1942 }
1943
1944 // EVR
1945 const char* evr = pakfire_package_get_string(pkg, PAKFIRE_PKG_EVR);
1946 if (evr) {
1947 r = pakfire_json_add_string(pkg->pakfire, md, "evr", evr);
1948 if (r)
1949 goto ERROR;
1950 }
1951
1952 // Arch
1953 const char* arch = pakfire_package_get_string(pkg, PAKFIRE_PKG_ARCH);
1954 if (arch) {
1955 r = pakfire_json_add_string(pkg->pakfire, md, "arch", arch);
1956 if (r)
1957 goto ERROR;
1958 }
1959
1960 // Vendor
1961 const char* vendor = pakfire_package_get_string(pkg, PAKFIRE_PKG_VENDOR);
1962 if (vendor) {
1963 r = pakfire_json_add_string(pkg->pakfire, md, "vendor", vendor);
1964 if (r)
1965 goto ERROR;
1966 }
1967
1968 // Distribution
1969 const char* distribution = pakfire_package_get_string(pkg, PAKFIRE_PKG_DISTRO);
1970 if (distribution) {
1971 r = pakfire_json_add_string(pkg->pakfire, md, "distribution", distribution);
1972 if (r)
1973 goto ERROR;
1974 }
1975
1976 // UUID
1977 const char* uuid = pakfire_package_get_string(pkg, PAKFIRE_PKG_UUID);
1978 if (uuid) {
1979 r = pakfire_json_add_string(pkg->pakfire, md, "uuid", uuid);
1980 if (r)
1981 goto ERROR;
1982 }
1983
1984 // Groups
1985 const char* groups = pakfire_package_get_string(pkg, PAKFIRE_PKG_GROUPS);
1986 if (groups) {
1987 r = pakfire_json_add_string(pkg->pakfire, md, "groups", groups);
1988 if (r)
1989 goto ERROR;
1990 }
1991
1992 // Packager
1993 const char* packager = pakfire_package_get_string(pkg, PAKFIRE_PKG_PACKAGER);
1994 if (packager) {
1995 r = pakfire_json_add_string(pkg->pakfire, md, "packager", packager);
1996 if (r)
1997 goto ERROR;
1998 }
1999
2000 // URL
2001 const char* url = pakfire_package_get_string(pkg, PAKFIRE_PKG_URL);
2002 if (url) {
2003 r = pakfire_json_add_string(pkg->pakfire, md, "url", url);
2004 if (r)
2005 goto ERROR;
2006 }
2007
2008 // License
2009 const char* license = pakfire_package_get_string(pkg, PAKFIRE_PKG_LICENSE);
2010 if (license) {
2011 r = pakfire_json_add_string(pkg->pakfire, md, "license", license);
2012 if (r)
2013 goto ERROR;
2014 }
2015
2016 // Summary
2017 const char* summary = pakfire_package_get_string(pkg, PAKFIRE_PKG_SUMMARY);
2018 if (summary) {
2019 r = pakfire_json_add_string(pkg->pakfire, md, "summary", summary);
2020 if (r)
2021 goto ERROR;
2022 }
2023
2024 // Description
2025 const char* description = pakfire_package_get_string(pkg, PAKFIRE_PKG_DESCRIPTION);
2026 if (description) {
2027 r = pakfire_json_add_string(pkg->pakfire, md, "description", description);
2028 if (r)
2029 goto ERROR;
2030 }
2031
2032 // Installed package size
2033 size_t installsize = pakfire_package_get_num(pkg, PAKFIRE_PKG_INSTALLSIZE, 0);
2034
2035 r = pakfire_json_add_integer(pkg->pakfire, md, "size", installsize);
2036 if (r)
2037 goto ERROR;
2038
2039 // Generate dependency metadata
2040 r = pakfire_package_add_json_dependencies(pkg, md);
2041 if (r)
2042 goto ERROR;
2043
2044 // Generate filelist
2045 r = pakfire_package_add_json_filelist(pkg, md);
2046 if (r)
2047 goto ERROR;
2048
2049 // Generate build metadata
2050 r = pakfire_package_add_build_metadata(pkg, md);
2051 if (r)
2052 goto ERROR;
2053
2054 ERROR:
2055 if (r)
2056 json_object_put(md);
2057
2058 return md;
2059 }