Refactor pkg_load/parse_descfile into a new backend file
[pacman-ng.git] / lib / libalpm / package.c
blob3989b76dc38fd03105f1c118d4a9d03a9d825a88
1 /*
2 * package.c
4 * Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org>
5 * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
6 * Copyright (c) 2005, 2006 by Christian Hamar <krics@linuxforum.hu>
7 * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "config.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <limits.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
35 /* libarchive */
36 #include <archive.h>
37 #include <archive_entry.h>
39 /* libalpm */
40 #include "package.h"
41 #include "alpm_list.h"
42 #include "log.h"
43 #include "util.h"
44 #include "db.h"
45 #include "cache.h"
46 #include "delta.h"
47 #include "handle.h"
48 #include "deps.h"
50 /** \addtogroup alpm_packages Package Functions
51 * @brief Functions to manipulate libalpm packages
52 * @{
55 /** Free a package.
56 * @param pkg package pointer to free
57 * @return 0 on success, -1 on error (pm_errno is set accordingly)
59 int SYMEXPORT alpm_pkg_free(pmpkg_t *pkg)
61 ALPM_LOG_FUNC;
63 ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
65 /* Only free packages loaded in user space */
66 if(pkg->origin != PKG_FROM_CACHE) {
67 _alpm_pkg_free(pkg);
70 return(0);
73 /** Check the integrity (with md5) of a package from the sync cache.
74 * @param pkg package pointer
75 * @return 0 on success, -1 on error (pm_errno is set accordingly)
77 int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg)
79 char *fpath;
80 int retval;
82 ALPM_LOG_FUNC;
84 ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1));
85 /* We only inspect packages from sync repositories */
86 ASSERT(pkg->origin == PKG_FROM_CACHE, RET_ERR(PM_ERR_PKG_INVALID, -1));
87 ASSERT(pkg->origin_data.db != handle->db_local, RET_ERR(PM_ERR_PKG_INVALID, -1));
89 fpath = _alpm_filecache_find(alpm_pkg_get_filename(pkg));
91 retval = _alpm_test_md5sum(fpath, alpm_pkg_get_md5sum(pkg));
93 if(retval == 0) {
94 return(0);
95 } else if (retval == 1) {
96 pm_errno = PM_ERR_PKG_INVALID;
97 retval = -1;
100 return(retval);
103 /** Compare versions.
104 * @param ver1 first version
105 * @param ver2 secont version
106 * @return postive, 0 or negative if ver1 is less, equal or more
107 * than ver2, respectively.
109 int SYMEXPORT alpm_pkg_vercmp(const char *ver1, const char *ver2)
111 ALPM_LOG_FUNC;
113 return(_alpm_versioncmp(ver1, ver2));
116 const char SYMEXPORT *alpm_pkg_get_filename(pmpkg_t *pkg)
118 ALPM_LOG_FUNC;
120 /* Sanity checks */
121 ASSERT(handle != NULL, return(NULL));
122 ASSERT(pkg != NULL, return(NULL));
124 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
125 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
128 return pkg->filename;
131 const char SYMEXPORT *alpm_pkg_get_name(pmpkg_t *pkg)
133 ALPM_LOG_FUNC;
135 /* Sanity checks */
136 ASSERT(handle != NULL, return(NULL));
137 ASSERT(pkg != NULL, return(NULL));
139 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_BASE)) {
140 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_BASE);
142 return pkg->name;
145 const char SYMEXPORT *alpm_pkg_get_version(pmpkg_t *pkg)
147 ALPM_LOG_FUNC;
149 /* Sanity checks */
150 ASSERT(handle != NULL, return(NULL));
151 ASSERT(pkg != NULL, return(NULL));
153 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_BASE)) {
154 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_BASE);
156 return pkg->version;
159 const char SYMEXPORT *alpm_pkg_get_desc(pmpkg_t *pkg)
161 ALPM_LOG_FUNC;
163 /* Sanity checks */
164 ASSERT(handle != NULL, return(NULL));
165 ASSERT(pkg != NULL, return(NULL));
167 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
168 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
170 return pkg->desc;
173 const char SYMEXPORT *alpm_pkg_get_url(pmpkg_t *pkg)
175 ALPM_LOG_FUNC;
177 /* Sanity checks */
178 ASSERT(handle != NULL, return(NULL));
179 ASSERT(pkg != NULL, return(NULL));
181 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
182 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
184 return pkg->url;
187 time_t SYMEXPORT alpm_pkg_get_builddate(pmpkg_t *pkg)
189 ALPM_LOG_FUNC;
191 /* Sanity checks */
192 ASSERT(handle != NULL, return(0));
193 ASSERT(pkg != NULL, return(0));
195 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
196 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
198 return pkg->builddate;
201 time_t SYMEXPORT alpm_pkg_get_installdate(pmpkg_t *pkg)
203 ALPM_LOG_FUNC;
205 /* Sanity checks */
206 ASSERT(handle != NULL, return(0));
207 ASSERT(pkg != NULL, return(0));
209 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
210 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
212 return pkg->installdate;
215 const char SYMEXPORT *alpm_pkg_get_packager(pmpkg_t *pkg)
217 ALPM_LOG_FUNC;
219 /* Sanity checks */
220 ASSERT(handle != NULL, return(NULL));
221 ASSERT(pkg != NULL, return(NULL));
223 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
224 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
226 return pkg->packager;
229 const char SYMEXPORT *alpm_pkg_get_md5sum(pmpkg_t *pkg)
231 ALPM_LOG_FUNC;
233 /* Sanity checks */
234 ASSERT(handle != NULL, return(NULL));
235 ASSERT(pkg != NULL, return(NULL));
237 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
238 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
240 return pkg->md5sum;
243 const char SYMEXPORT *alpm_pkg_get_arch(pmpkg_t *pkg)
245 ALPM_LOG_FUNC;
247 /* Sanity checks */
248 ASSERT(handle != NULL, return(NULL));
249 ASSERT(pkg != NULL, return(NULL));
251 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
252 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
254 return pkg->arch;
257 unsigned long SYMEXPORT alpm_pkg_get_size(pmpkg_t *pkg)
259 ALPM_LOG_FUNC;
261 /* Sanity checks */
262 ASSERT(handle != NULL, return(-1));
263 ASSERT(pkg != NULL, return(-1));
265 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
266 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
268 return pkg->size;
271 unsigned long SYMEXPORT alpm_pkg_get_isize(pmpkg_t *pkg)
273 ALPM_LOG_FUNC;
275 /* Sanity checks */
276 ASSERT(handle != NULL, return(-1));
277 ASSERT(pkg != NULL, return(-1));
279 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
280 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
282 return pkg->isize;
285 pmpkgreason_t SYMEXPORT alpm_pkg_get_reason(pmpkg_t *pkg)
287 ALPM_LOG_FUNC;
289 /* Sanity checks */
290 ASSERT(handle != NULL, return(-1));
291 ASSERT(pkg != NULL, return(-1));
293 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
294 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
296 return pkg->reason;
299 alpm_list_t SYMEXPORT *alpm_pkg_get_licenses(pmpkg_t *pkg)
301 ALPM_LOG_FUNC;
303 /* Sanity checks */
304 ASSERT(handle != NULL, return(NULL));
305 ASSERT(pkg != NULL, return(NULL));
307 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
308 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
310 return pkg->licenses;
313 alpm_list_t SYMEXPORT *alpm_pkg_get_groups(pmpkg_t *pkg)
315 ALPM_LOG_FUNC;
317 /* Sanity checks */
318 ASSERT(handle != NULL, return(NULL));
319 ASSERT(pkg != NULL, return(NULL));
321 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
322 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
324 return pkg->groups;
327 alpm_list_t SYMEXPORT *alpm_pkg_get_depends(pmpkg_t *pkg)
329 ALPM_LOG_FUNC;
331 /* Sanity checks */
332 ASSERT(handle != NULL, return(NULL));
333 ASSERT(pkg != NULL, return(NULL));
335 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
336 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
338 return pkg->depends;
341 alpm_list_t SYMEXPORT *alpm_pkg_get_optdepends(pmpkg_t *pkg)
343 ALPM_LOG_FUNC;
345 /* Sanity checks */
346 ASSERT(handle != NULL, return(NULL));
347 ASSERT(pkg != NULL, return(NULL));
349 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
350 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
352 return pkg->optdepends;
355 alpm_list_t SYMEXPORT *alpm_pkg_get_conflicts(pmpkg_t *pkg)
357 ALPM_LOG_FUNC;
359 /* Sanity checks */
360 ASSERT(handle != NULL, return(NULL));
361 ASSERT(pkg != NULL, return(NULL));
363 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
364 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
366 return pkg->conflicts;
369 alpm_list_t SYMEXPORT *alpm_pkg_get_provides(pmpkg_t *pkg)
371 ALPM_LOG_FUNC;
373 /* Sanity checks */
374 ASSERT(handle != NULL, return(NULL));
375 ASSERT(pkg != NULL, return(NULL));
377 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
378 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DEPENDS);
380 return pkg->provides;
383 alpm_list_t SYMEXPORT *alpm_pkg_get_deltas(pmpkg_t *pkg)
385 ALPM_LOG_FUNC;
387 /* Sanity checks */
388 ASSERT(handle != NULL, return(NULL));
389 ASSERT(pkg != NULL, return(NULL));
391 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DELTAS)) {
392 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DELTAS);
394 return pkg->deltas;
397 alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(pmpkg_t *pkg)
399 ALPM_LOG_FUNC;
401 /* Sanity checks */
402 ASSERT(handle != NULL, return(NULL));
403 ASSERT(pkg != NULL, return(NULL));
405 if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DESC)) {
406 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
408 return pkg->replaces;
411 alpm_list_t SYMEXPORT *alpm_pkg_get_files(pmpkg_t *pkg)
413 ALPM_LOG_FUNC;
415 /* Sanity checks */
416 ASSERT(handle != NULL, return(NULL));
417 ASSERT(pkg != NULL, return(NULL));
419 if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local
420 && !(pkg->infolevel & INFRQ_FILES)) {
421 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
423 return pkg->files;
426 alpm_list_t SYMEXPORT *alpm_pkg_get_backup(pmpkg_t *pkg)
428 ALPM_LOG_FUNC;
430 /* Sanity checks */
431 ASSERT(handle != NULL, return(NULL));
432 ASSERT(pkg != NULL, return(NULL));
434 if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local
435 && !(pkg->infolevel & INFRQ_FILES)) {
436 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
438 return pkg->backup;
442 * Open a package changelog for reading. Similar to fopen in functionality,
443 * except that the returned 'file stream' could really be from an archive
444 * as well as from the database.
445 * @param pkg the package to read the changelog of (either file or db)
446 * @return a 'file stream' to the package changelog
448 void SYMEXPORT *alpm_pkg_changelog_open(pmpkg_t *pkg)
450 ALPM_LOG_FUNC;
452 /* Sanity checks */
453 ASSERT(handle != NULL, return(NULL));
454 ASSERT(pkg != NULL, return(NULL));
456 if(pkg->origin == PKG_FROM_CACHE) {
457 char clfile[PATH_MAX];
458 snprintf(clfile, PATH_MAX, "%s/%s/%s-%s/changelog",
459 alpm_option_get_dbpath(),
460 alpm_db_get_name(handle->db_local),
461 alpm_pkg_get_name(pkg),
462 alpm_pkg_get_version(pkg));
463 return fopen(clfile, "r");
464 } else if(pkg->origin == PKG_FROM_FILE) {
465 struct archive *archive = NULL;
466 struct archive_entry *entry;
467 const char *pkgfile = pkg->origin_data.file;
468 int ret = ARCHIVE_OK;
470 if((archive = archive_read_new()) == NULL) {
471 RET_ERR(PM_ERR_LIBARCHIVE, NULL);
474 archive_read_support_compression_all(archive);
475 archive_read_support_format_all(archive);
477 if (archive_read_open_filename(archive, pkgfile,
478 ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
479 RET_ERR(PM_ERR_PKG_OPEN, NULL);
482 while((ret = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
483 const char *entry_name = archive_entry_pathname(entry);
485 if(strcmp(entry_name, ".CHANGELOG") == 0) {
486 return(archive);
489 /* we didn't find a changelog */
490 archive_read_finish(archive);
491 errno = ENOENT;
493 return(NULL);
497 * Read data from an open changelog 'file stream'. Similar to fread in
498 * functionality, this function takes a buffer and amount of data to read.
499 * @param ptr a buffer to fill with raw changelog data
500 * @param size the size of the buffer
501 * @param pkg the package that the changelog is being read from
502 * @param fp a 'file stream' to the package changelog
503 * @return the number of characters read, or 0 if there is no more data
505 size_t SYMEXPORT alpm_pkg_changelog_read(void *ptr, size_t size,
506 const pmpkg_t *pkg, const void *fp)
508 size_t ret = 0;
509 if(pkg->origin == PKG_FROM_CACHE) {
510 ret = fread(ptr, 1, size, (FILE*)fp);
511 } else if(pkg->origin == PKG_FROM_FILE) {
512 ret = archive_read_data((struct archive*)fp, ptr, size);
514 return(ret);
518 int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)
520 int ret = 0;
521 if(pkg->origin == PKG_FROM_CACHE) {
522 ret = feof((FILE*)fp);
523 } else if(pkg->origin == PKG_FROM_FILE) {
524 // note: this doesn't quite work, no feof in libarchive
525 ret = archive_read_data((struct archive*)fp, NULL, 0);
527 return(ret);
532 * Close a package changelog for reading. Similar to fclose in functionality,
533 * except that the 'file stream' could really be from an archive as well as
534 * from the database.
535 * @param pkg the package that the changelog was read from
536 * @param fp a 'file stream' to the package changelog
537 * @return whether closing the package changelog stream was successful
539 int SYMEXPORT alpm_pkg_changelog_close(const pmpkg_t *pkg, void *fp)
541 int ret = 0;
542 if(pkg->origin == PKG_FROM_CACHE) {
543 ret = fclose((FILE*)fp);
544 } else if(pkg->origin == PKG_FROM_FILE) {
545 ret = archive_read_finish((struct archive *)fp);
547 return(ret);
550 unsigned short SYMEXPORT alpm_pkg_has_scriptlet(pmpkg_t *pkg)
552 ALPM_LOG_FUNC;
554 /* Sanity checks */
555 ASSERT(handle != NULL, return(-1));
556 ASSERT(pkg != NULL, return(-1));
558 if(pkg->origin == PKG_FROM_CACHE && pkg->origin_data.db == handle->db_local
559 && !(pkg->infolevel & INFRQ_SCRIPTLET)) {
560 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_SCRIPTLET);
562 return pkg->scriptlet;
566 * @brief Compute the packages requiring a given package.
567 * @param pkg a package
568 * @return the list of packages requiring pkg
570 * A depends on B through n depends <=> A listed in B's requiredby n times
571 * n == 0 or 1 in almost all cases */
572 alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(pmpkg_t *pkg)
574 const alpm_list_t *i, *j;
575 alpm_list_t *reqs = NULL;
577 pmdb_t *localdb = alpm_option_get_localdb();
578 for(i = _alpm_db_get_pkgcache(localdb); i; i = i->next) {
579 if(!i->data) {
580 continue;
582 pmpkg_t *cachepkg = i->data;
583 const char *cachepkgname = alpm_pkg_get_name(cachepkg);
585 for(j = alpm_pkg_get_depends(cachepkg); j; j = j->next) {
586 pmdepend_t *dep = j->data;
588 if(alpm_depcmp(pkg, dep)) {
589 _alpm_log(PM_LOG_DEBUG, "adding '%s' in requiredby field for '%s'\n",
590 cachepkgname, pkg->name);
591 reqs = alpm_list_add(reqs, strdup(cachepkgname));
595 return(reqs);
598 /** @} */
600 /* this function was taken from rpm 4.0.4 and rewritten */
601 int _alpm_versioncmp(const char *a, const char *b)
603 char str1[64], str2[64];
604 char *ptr1, *ptr2;
605 char *one, *two;
606 char *rel1 = NULL, *rel2 = NULL;
607 char oldch1, oldch2;
608 int is1num, is2num;
609 int rc;
611 ALPM_LOG_FUNC;
613 if(!strcmp(a,b)) {
614 return(0);
617 strncpy(str1, a, 64);
618 str1[63] = 0;
619 strncpy(str2, b, 64);
620 str2[63] = 0;
622 /* lose the release number */
623 for(one = str1; *one && *one != '-'; one++);
624 if(one) {
625 *one = '\0';
626 rel1 = ++one;
628 for(two = str2; *two && *two != '-'; two++);
629 if(two) {
630 *two = '\0';
631 rel2 = ++two;
634 one = str1;
635 two = str2;
637 while(*one || *two) {
638 while(*one && !isalnum((int)*one)) one++;
639 while(*two && !isalnum((int)*two)) two++;
641 ptr1 = one;
642 ptr2 = two;
644 /* find the next segment for each string */
645 if(isdigit((int)*ptr1)) {
646 is1num = 1;
647 while(*ptr1 && isdigit((int)*ptr1)) ptr1++;
648 } else {
649 is1num = 0;
650 while(*ptr1 && isalpha((int)*ptr1)) ptr1++;
652 if(isdigit((int)*ptr2)) {
653 is2num = 1;
654 while(*ptr2 && isdigit((int)*ptr2)) ptr2++;
655 } else {
656 is2num = 0;
657 while(*ptr2 && isalpha((int)*ptr2)) ptr2++;
660 oldch1 = *ptr1;
661 *ptr1 = '\0';
662 oldch2 = *ptr2;
663 *ptr2 = '\0';
665 /* see if we ran out of segments on one string */
666 if(one == ptr1 && two != ptr2) {
667 return(is2num ? -1 : 1);
669 if(one != ptr1 && two == ptr2) {
670 return(is1num ? 1 : -1);
673 /* see if we have a type mismatch (ie, one is alpha and one is digits) */
674 if(is1num && !is2num) return(1);
675 if(!is1num && is2num) return(-1);
677 if(is1num) while(*one == '0') one++;
678 if(is2num) while(*two == '0') two++;
680 rc = strverscmp(one, two);
681 if(rc) return(rc);
683 *ptr1 = oldch1;
684 *ptr2 = oldch2;
685 one = ptr1;
686 two = ptr2;
689 if((!*one) && (!*two)) {
690 /* compare release numbers */
691 if(rel1 && rel2 && strlen(rel1) && strlen(rel2)) return(_alpm_versioncmp(rel1, rel2));
692 return(0);
695 return(*one ? 1 : -1);
699 pmpkg_t *_alpm_pkg_new(const char *name, const char *version)
701 pmpkg_t* pkg;
703 ALPM_LOG_FUNC;
705 CALLOC(pkg, 1, sizeof(pmpkg_t), RET_ERR(PM_ERR_MEMORY, NULL));
707 if(name) {
708 STRDUP(pkg->name, name, RET_ERR(PM_ERR_MEMORY, pkg));
711 if(version) {
712 STRDUP(pkg->version, version, RET_ERR(PM_ERR_MEMORY, pkg));
715 return(pkg);
718 pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)
720 pmpkg_t *newpkg;
721 alpm_list_t *i;
723 ALPM_LOG_FUNC;
725 CALLOC(newpkg, 1, sizeof(pmpkg_t), RET_ERR(PM_ERR_MEMORY, NULL));
727 STRDUP(newpkg->filename, pkg->filename, RET_ERR(PM_ERR_MEMORY, newpkg));
728 STRDUP(newpkg->name, pkg->name, RET_ERR(PM_ERR_MEMORY, newpkg));
729 STRDUP(newpkg->version, pkg->version, RET_ERR(PM_ERR_MEMORY, newpkg));
730 STRDUP(newpkg->desc, pkg->desc, RET_ERR(PM_ERR_MEMORY, newpkg));
731 STRDUP(newpkg->url, pkg->url, RET_ERR(PM_ERR_MEMORY, newpkg));
732 newpkg->builddate = pkg->builddate;
733 newpkg->installdate = pkg->installdate;
734 STRDUP(newpkg->packager, pkg->packager, RET_ERR(PM_ERR_MEMORY, newpkg));
735 STRDUP(newpkg->md5sum, pkg->md5sum, RET_ERR(PM_ERR_MEMORY, newpkg));
736 STRDUP(newpkg->arch, pkg->arch, RET_ERR(PM_ERR_MEMORY, newpkg));
737 newpkg->size = pkg->size;
738 newpkg->isize = pkg->isize;
739 newpkg->scriptlet = pkg->scriptlet;
740 newpkg->force = pkg->force;
741 newpkg->reason = pkg->reason;
743 newpkg->licenses = alpm_list_strdup(alpm_pkg_get_licenses(pkg));
744 newpkg->replaces = alpm_list_strdup(alpm_pkg_get_replaces(pkg));
745 newpkg->groups = alpm_list_strdup(alpm_pkg_get_groups(pkg));
746 newpkg->files = alpm_list_strdup(alpm_pkg_get_files(pkg));
747 newpkg->backup = alpm_list_strdup(alpm_pkg_get_backup(pkg));
748 for(i = alpm_pkg_get_depends(pkg); i; i = alpm_list_next(i)) {
749 newpkg->depends = alpm_list_add(newpkg->depends, _alpm_dep_dup(i->data));
751 newpkg->optdepends = alpm_list_strdup(alpm_pkg_get_optdepends(pkg));
752 newpkg->conflicts = alpm_list_strdup(alpm_pkg_get_conflicts(pkg));
753 newpkg->provides = alpm_list_strdup(alpm_pkg_get_provides(pkg));
754 newpkg->deltas = alpm_list_copy_data(alpm_pkg_get_deltas(pkg),
755 sizeof(pmdelta_t));
757 /* internal */
758 newpkg->origin = pkg->origin;
759 if(newpkg->origin == PKG_FROM_FILE) {
760 newpkg->origin_data.file = strdup(pkg->origin_data.file);
761 } else {
762 newpkg->origin_data.db = pkg->origin_data.db;
764 newpkg->infolevel = pkg->infolevel;
766 return(newpkg);
769 void _alpm_pkg_free(pmpkg_t *pkg)
771 ALPM_LOG_FUNC;
773 if(pkg == NULL) {
774 return;
777 FREE(pkg->filename);
778 FREE(pkg->name);
779 FREE(pkg->version);
780 FREE(pkg->desc);
781 FREE(pkg->url);
782 FREE(pkg->packager);
783 FREE(pkg->md5sum);
784 FREE(pkg->arch);
785 FREELIST(pkg->licenses);
786 FREELIST(pkg->replaces);
787 FREELIST(pkg->groups);
788 FREELIST(pkg->files);
789 FREELIST(pkg->backup);
790 alpm_list_free_inner(pkg->depends, (alpm_list_fn_free)_alpm_dep_free);
791 alpm_list_free(pkg->depends);
792 FREELIST(pkg->optdepends);
793 FREELIST(pkg->conflicts);
794 FREELIST(pkg->provides);
795 alpm_list_free_inner(pkg->deltas, (alpm_list_fn_free)_alpm_delta_free);
796 alpm_list_free(pkg->deltas);
797 alpm_list_free(pkg->delta_path);
799 if(pkg->origin == PKG_FROM_FILE) {
800 FREE(pkg->origin_data.file);
802 FREE(pkg);
805 /* Is pkgB an upgrade for pkgA ? */
806 int _alpm_pkg_compare_versions(pmpkg_t *local_pkg, pmpkg_t *pkg)
808 int cmp = 0;
810 ALPM_LOG_FUNC;
812 if(pkg->origin == PKG_FROM_CACHE) {
813 /* ensure we have the /desc file, which contains the 'force' option */
814 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC);
817 /* compare versions and see if we need to upgrade */
818 cmp = _alpm_versioncmp(alpm_pkg_get_version(pkg), alpm_pkg_get_version(local_pkg));
820 if(cmp != 0 && pkg->force) {
821 cmp = 1;
822 _alpm_log(PM_LOG_WARNING, _("%s: forcing upgrade to version %s\n"),
823 alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg));
824 } else if(cmp < 0) {
825 /* local version is newer */
826 pmdb_t *db = pkg->origin_data.db;
827 _alpm_log(PM_LOG_WARNING, _("%s: local (%s) is newer than %s (%s)\n"),
828 alpm_pkg_get_name(local_pkg), alpm_pkg_get_version(local_pkg),
829 alpm_db_get_name(db), alpm_pkg_get_version(pkg));
830 cmp = 0;
833 return(cmp);
836 /* Helper function for comparing packages
838 int _alpm_pkg_cmp(const void *p1, const void *p2)
840 pmpkg_t *pk1 = (pmpkg_t *)p1;
841 pmpkg_t *pk2 = (pmpkg_t *)p2;
843 return(strcmp(alpm_pkg_get_name(pk1), alpm_pkg_get_name(pk2)));
846 int _alpm_pkgname_pkg_cmp(const void *pkgname, const void *package)
848 return(strcmp(alpm_pkg_get_name((pmpkg_t *) package), (char *) pkgname));
851 /* Test for existence of a package in a alpm_list_t*
852 * of pmpkg_t*
854 pmpkg_t *_alpm_pkg_find(const char *needle, alpm_list_t *haystack)
856 alpm_list_t *lp;
858 ALPM_LOG_FUNC;
860 if(needle == NULL || haystack == NULL) {
861 return(NULL);
864 for(lp = haystack; lp; lp = lp->next) {
865 pmpkg_t *info = lp->data;
867 if(info && strcmp(alpm_pkg_get_name(info), needle) == 0) {
868 return(info);
871 return(NULL);
874 /** Test if a package should be ignored.
876 * Checks if the package is ignored via IgnorePkg, or if the package is
877 * in a group ignored via IgnoreGrp.
879 * @param pkg the package to test
881 * @return 1 if the package should be ignored, 0 otherwise
883 int _alpm_pkg_should_ignore(pmpkg_t *pkg)
885 alpm_list_t *groups = NULL;
887 /* first see if the package is ignored */
888 if(alpm_list_find_str(handle->ignorepkg, alpm_pkg_get_name(pkg))) {
889 return(1);
892 /* next see if the package is in a group that is ignored */
893 for(groups = handle->ignoregrp; groups; groups = alpm_list_next(groups)) {
894 char *grp = (char *)alpm_list_getdata(groups);
895 if(alpm_list_find_str(alpm_pkg_get_groups(pkg), grp)) {
896 return(1);
900 return(0);
903 /* vim: set ts=2 sw=2 noet: */