4 * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
6 * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
7 * Copyright (c) 2005, 2006 by Christian Hamar <krics@linuxforum.hu>
8 * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include <sys/types.h>
32 #include "alpm_list.h"
40 /** \addtogroup alpm_packages Package Functions
41 * @brief Functions to manipulate libalpm packages
45 /** Free a package. */
46 int SYMEXPORT
alpm_pkg_free(pmpkg_t
*pkg
)
48 ASSERT(pkg
!= NULL
, return -1);
50 /* Only free packages loaded in user space */
51 if(pkg
->origin
== PKG_FROM_FILE
) {
58 /** Check the integrity (with md5) of a package from the sync cache. */
59 int SYMEXPORT
alpm_pkg_checkmd5sum(pmpkg_t
*pkg
)
64 ASSERT(pkg
!= NULL
, return -1);
65 pkg
->handle
->pm_errno
= 0;
66 /* We only inspect packages from sync repositories */
67 ASSERT(pkg
->origin
== PKG_FROM_SYNCDB
,
68 RET_ERR(pkg
->handle
, PM_ERR_WRONG_ARGS
, -1));
70 fpath
= _alpm_filecache_find(pkg
->handle
, alpm_pkg_get_filename(pkg
));
72 retval
= _alpm_test_md5sum(fpath
, alpm_pkg_get_md5sum(pkg
));
76 } else if(retval
== 1) {
77 pkg
->handle
->pm_errno
= PM_ERR_PKG_INVALID
;
84 /* Default package accessor functions. These will get overridden by any
85 * backend logic that needs lazy access, such as the local database through
86 * a lazy-load cache. However, the defaults will work just fine for fully-
87 * populated package structures. */
88 static const char *_pkg_get_filename(pmpkg_t
*pkg
) { return pkg
->filename
; }
89 static const char *_pkg_get_desc(pmpkg_t
*pkg
) { return pkg
->desc
; }
90 static const char *_pkg_get_url(pmpkg_t
*pkg
) { return pkg
->url
; }
91 static time_t _pkg_get_builddate(pmpkg_t
*pkg
) { return pkg
->builddate
; }
92 static time_t _pkg_get_installdate(pmpkg_t
*pkg
) { return pkg
->installdate
; }
93 static const char *_pkg_get_packager(pmpkg_t
*pkg
) { return pkg
->packager
; }
94 static const char *_pkg_get_md5sum(pmpkg_t
*pkg
) { return pkg
->md5sum
; }
95 static const char *_pkg_get_arch(pmpkg_t
*pkg
) { return pkg
->arch
; }
96 static off_t
_pkg_get_size(pmpkg_t
*pkg
) { return pkg
->size
; }
97 static off_t
_pkg_get_isize(pmpkg_t
*pkg
) { return pkg
->isize
; }
98 static alpm_pkgreason_t
_pkg_get_reason(pmpkg_t
*pkg
) { return pkg
->reason
; }
99 static int _pkg_has_scriptlet(pmpkg_t
*pkg
) { return pkg
->scriptlet
; }
101 static alpm_list_t
*_pkg_get_licenses(pmpkg_t
*pkg
) { return pkg
->licenses
; }
102 static alpm_list_t
*_pkg_get_groups(pmpkg_t
*pkg
) { return pkg
->groups
; }
103 static alpm_list_t
*_pkg_get_depends(pmpkg_t
*pkg
) { return pkg
->depends
; }
104 static alpm_list_t
*_pkg_get_optdepends(pmpkg_t
*pkg
) { return pkg
->optdepends
; }
105 static alpm_list_t
*_pkg_get_conflicts(pmpkg_t
*pkg
) { return pkg
->conflicts
; }
106 static alpm_list_t
*_pkg_get_provides(pmpkg_t
*pkg
) { return pkg
->provides
; }
107 static alpm_list_t
*_pkg_get_replaces(pmpkg_t
*pkg
) { return pkg
->replaces
; }
108 static alpm_list_t
*_pkg_get_deltas(pmpkg_t
*pkg
) { return pkg
->deltas
; }
109 static alpm_list_t
*_pkg_get_files(pmpkg_t
*pkg
) { return pkg
->files
; }
110 static alpm_list_t
*_pkg_get_backup(pmpkg_t
*pkg
) { return pkg
->backup
; }
112 static void *_pkg_changelog_open(pmpkg_t UNUSED
*pkg
)
117 static size_t _pkg_changelog_read(void UNUSED
*ptr
, size_t UNUSED size
,
118 const pmpkg_t UNUSED
*pkg
, const UNUSED
void *fp
)
123 static int _pkg_changelog_close(const pmpkg_t UNUSED
*pkg
,
129 /** The standard package operations struct. Get fields directly from the
130 * struct itself with no abstraction layer or any type of lazy loading.
132 struct pkg_operations default_pkg_ops
= {
133 .get_filename
= _pkg_get_filename
,
134 .get_desc
= _pkg_get_desc
,
135 .get_url
= _pkg_get_url
,
136 .get_builddate
= _pkg_get_builddate
,
137 .get_installdate
= _pkg_get_installdate
,
138 .get_packager
= _pkg_get_packager
,
139 .get_md5sum
= _pkg_get_md5sum
,
140 .get_arch
= _pkg_get_arch
,
141 .get_size
= _pkg_get_size
,
142 .get_isize
= _pkg_get_isize
,
143 .get_reason
= _pkg_get_reason
,
144 .has_scriptlet
= _pkg_has_scriptlet
,
146 .get_licenses
= _pkg_get_licenses
,
147 .get_groups
= _pkg_get_groups
,
148 .get_depends
= _pkg_get_depends
,
149 .get_optdepends
= _pkg_get_optdepends
,
150 .get_conflicts
= _pkg_get_conflicts
,
151 .get_provides
= _pkg_get_provides
,
152 .get_replaces
= _pkg_get_replaces
,
153 .get_deltas
= _pkg_get_deltas
,
154 .get_files
= _pkg_get_files
,
155 .get_backup
= _pkg_get_backup
,
157 .changelog_open
= _pkg_changelog_open
,
158 .changelog_read
= _pkg_changelog_read
,
159 .changelog_close
= _pkg_changelog_close
,
162 /* Public functions for getting package information. These functions
163 * delegate the hard work to the function callbacks attached to each
164 * package, which depend on where the package was loaded from. */
165 const char SYMEXPORT
*alpm_pkg_get_filename(pmpkg_t
*pkg
)
167 ASSERT(pkg
!= NULL
, return NULL
);
168 pkg
->handle
->pm_errno
= 0;
169 return pkg
->ops
->get_filename(pkg
);
172 const char SYMEXPORT
*alpm_pkg_get_name(pmpkg_t
*pkg
)
174 ASSERT(pkg
!= NULL
, return NULL
);
175 pkg
->handle
->pm_errno
= 0;
179 const char SYMEXPORT
*alpm_pkg_get_version(pmpkg_t
*pkg
)
181 ASSERT(pkg
!= NULL
, return NULL
);
182 pkg
->handle
->pm_errno
= 0;
186 const char SYMEXPORT
*alpm_pkg_get_desc(pmpkg_t
*pkg
)
188 ASSERT(pkg
!= NULL
, return NULL
);
189 pkg
->handle
->pm_errno
= 0;
190 return pkg
->ops
->get_desc(pkg
);
193 const char SYMEXPORT
*alpm_pkg_get_url(pmpkg_t
*pkg
)
195 ASSERT(pkg
!= NULL
, return NULL
);
196 pkg
->handle
->pm_errno
= 0;
197 return pkg
->ops
->get_url(pkg
);
200 time_t SYMEXPORT
alpm_pkg_get_builddate(pmpkg_t
*pkg
)
202 ASSERT(pkg
!= NULL
, return -1);
203 pkg
->handle
->pm_errno
= 0;
204 return pkg
->ops
->get_builddate(pkg
);
207 time_t SYMEXPORT
alpm_pkg_get_installdate(pmpkg_t
*pkg
)
209 ASSERT(pkg
!= NULL
, return -1);
210 pkg
->handle
->pm_errno
= 0;
211 return pkg
->ops
->get_installdate(pkg
);
214 const char SYMEXPORT
*alpm_pkg_get_packager(pmpkg_t
*pkg
)
216 ASSERT(pkg
!= NULL
, return NULL
);
217 pkg
->handle
->pm_errno
= 0;
218 return pkg
->ops
->get_packager(pkg
);
221 const char SYMEXPORT
*alpm_pkg_get_md5sum(pmpkg_t
*pkg
)
223 ASSERT(pkg
!= NULL
, return NULL
);
224 pkg
->handle
->pm_errno
= 0;
225 return pkg
->ops
->get_md5sum(pkg
);
228 const char SYMEXPORT
*alpm_pkg_get_arch(pmpkg_t
*pkg
)
230 ASSERT(pkg
!= NULL
, return NULL
);
231 pkg
->handle
->pm_errno
= 0;
232 return pkg
->ops
->get_arch(pkg
);
235 off_t SYMEXPORT
alpm_pkg_get_size(pmpkg_t
*pkg
)
237 ASSERT(pkg
!= NULL
, return -1);
238 pkg
->handle
->pm_errno
= 0;
239 return pkg
->ops
->get_size(pkg
);
242 off_t SYMEXPORT
alpm_pkg_get_isize(pmpkg_t
*pkg
)
244 ASSERT(pkg
!= NULL
, return -1);
245 pkg
->handle
->pm_errno
= 0;
246 return pkg
->ops
->get_isize(pkg
);
249 alpm_pkgreason_t SYMEXPORT
alpm_pkg_get_reason(pmpkg_t
*pkg
)
251 ASSERT(pkg
!= NULL
, return -1);
252 pkg
->handle
->pm_errno
= 0;
253 return pkg
->ops
->get_reason(pkg
);
256 alpm_list_t SYMEXPORT
*alpm_pkg_get_licenses(pmpkg_t
*pkg
)
258 ASSERT(pkg
!= NULL
, return NULL
);
259 pkg
->handle
->pm_errno
= 0;
260 return pkg
->ops
->get_licenses(pkg
);
263 alpm_list_t SYMEXPORT
*alpm_pkg_get_groups(pmpkg_t
*pkg
)
265 ASSERT(pkg
!= NULL
, return NULL
);
266 pkg
->handle
->pm_errno
= 0;
267 return pkg
->ops
->get_groups(pkg
);
270 alpm_list_t SYMEXPORT
*alpm_pkg_get_depends(pmpkg_t
*pkg
)
272 ASSERT(pkg
!= NULL
, return NULL
);
273 pkg
->handle
->pm_errno
= 0;
274 return pkg
->ops
->get_depends(pkg
);
277 alpm_list_t SYMEXPORT
*alpm_pkg_get_optdepends(pmpkg_t
*pkg
)
279 ASSERT(pkg
!= NULL
, return NULL
);
280 pkg
->handle
->pm_errno
= 0;
281 return pkg
->ops
->get_optdepends(pkg
);
284 alpm_list_t SYMEXPORT
*alpm_pkg_get_conflicts(pmpkg_t
*pkg
)
286 ASSERT(pkg
!= NULL
, return NULL
);
287 pkg
->handle
->pm_errno
= 0;
288 return pkg
->ops
->get_conflicts(pkg
);
291 alpm_list_t SYMEXPORT
*alpm_pkg_get_provides(pmpkg_t
*pkg
)
293 ASSERT(pkg
!= NULL
, return NULL
);
294 pkg
->handle
->pm_errno
= 0;
295 return pkg
->ops
->get_provides(pkg
);
298 alpm_list_t SYMEXPORT
*alpm_pkg_get_replaces(pmpkg_t
*pkg
)
300 ASSERT(pkg
!= NULL
, return NULL
);
301 pkg
->handle
->pm_errno
= 0;
302 return pkg
->ops
->get_replaces(pkg
);
305 alpm_list_t SYMEXPORT
*alpm_pkg_get_deltas(pmpkg_t
*pkg
)
307 ASSERT(pkg
!= NULL
, return NULL
);
308 pkg
->handle
->pm_errno
= 0;
309 return pkg
->ops
->get_deltas(pkg
);
312 alpm_list_t SYMEXPORT
*alpm_pkg_get_files(pmpkg_t
*pkg
)
314 ASSERT(pkg
!= NULL
, return NULL
);
315 pkg
->handle
->pm_errno
= 0;
316 return pkg
->ops
->get_files(pkg
);
319 alpm_list_t SYMEXPORT
*alpm_pkg_get_backup(pmpkg_t
*pkg
)
321 ASSERT(pkg
!= NULL
, return NULL
);
322 pkg
->handle
->pm_errno
= 0;
323 return pkg
->ops
->get_backup(pkg
);
326 pmdb_t SYMEXPORT
*alpm_pkg_get_db(pmpkg_t
*pkg
)
329 ASSERT(pkg
!= NULL
, return NULL
);
330 ASSERT(pkg
->origin
!= PKG_FROM_FILE
, return NULL
);
331 pkg
->handle
->pm_errno
= 0;
333 return pkg
->origin_data
.db
;
336 /** Open a package changelog for reading. */
337 void SYMEXPORT
*alpm_pkg_changelog_open(pmpkg_t
*pkg
)
339 ASSERT(pkg
!= NULL
, return NULL
);
340 pkg
->handle
->pm_errno
= 0;
341 return pkg
->ops
->changelog_open(pkg
);
344 /** Read data from an open changelog 'file stream'. */
345 size_t SYMEXPORT
alpm_pkg_changelog_read(void *ptr
, size_t size
,
346 const pmpkg_t
*pkg
, const void *fp
)
348 ASSERT(pkg
!= NULL
, return 0);
349 pkg
->handle
->pm_errno
= 0;
350 return pkg
->ops
->changelog_read(ptr
, size
, pkg
, fp
);
354 int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)
356 return pkg->ops->changelog_feof(pkg, fp);
360 /** Close a package changelog for reading. */
361 int SYMEXPORT
alpm_pkg_changelog_close(const pmpkg_t
*pkg
, void *fp
)
363 ASSERT(pkg
!= NULL
, return -1);
364 pkg
->handle
->pm_errno
= 0;
365 return pkg
->ops
->changelog_close(pkg
, fp
);
368 int SYMEXPORT
alpm_pkg_has_scriptlet(pmpkg_t
*pkg
)
370 ASSERT(pkg
!= NULL
, return -1);
371 pkg
->handle
->pm_errno
= 0;
372 return pkg
->ops
->has_scriptlet(pkg
);
375 static void find_requiredby(pmpkg_t
*pkg
, pmdb_t
*db
, alpm_list_t
**reqs
)
377 const alpm_list_t
*i
;
378 pkg
->handle
->pm_errno
= 0;
380 for(i
= _alpm_db_get_pkgcache(db
); i
; i
= i
->next
) {
381 pmpkg_t
*cachepkg
= i
->data
;
383 for(j
= alpm_pkg_get_depends(cachepkg
); j
; j
= j
->next
) {
384 if(_alpm_depcmp(pkg
, j
->data
)) {
385 const char *cachepkgname
= cachepkg
->name
;
386 if(alpm_list_find_str(*reqs
, cachepkgname
) == NULL
) {
387 *reqs
= alpm_list_add(*reqs
, strdup(cachepkgname
));
394 /** Compute the packages requiring a given package. */
395 alpm_list_t SYMEXPORT
*alpm_pkg_compute_requiredby(pmpkg_t
*pkg
)
397 const alpm_list_t
*i
;
398 alpm_list_t
*reqs
= NULL
;
401 ASSERT(pkg
!= NULL
, return NULL
);
402 pkg
->handle
->pm_errno
= 0;
404 if(pkg
->origin
== PKG_FROM_FILE
) {
405 /* The sane option; search locally for things that require this. */
406 find_requiredby(pkg
, pkg
->handle
->db_local
, &reqs
);
408 /* We have a DB package. if it is a local package, then we should
409 * only search the local DB; else search all known sync databases. */
410 db
= pkg
->origin_data
.db
;
412 find_requiredby(pkg
, db
, &reqs
);
414 for(i
= pkg
->handle
->dbs_sync
; i
; i
= i
->next
) {
416 find_requiredby(pkg
, db
, &reqs
);
418 reqs
= alpm_list_msort(reqs
, alpm_list_count(reqs
), _alpm_str_cmp
);
426 pmpkg_t
*_alpm_pkg_new(void)
430 CALLOC(pkg
, 1, sizeof(pmpkg_t
), return NULL
);
435 pmpkg_t
*_alpm_pkg_dup(pmpkg_t
*pkg
)
440 CALLOC(newpkg
, 1, sizeof(pmpkg_t
), goto cleanup
);
442 newpkg
->name_hash
= pkg
->name_hash
;
443 STRDUP(newpkg
->filename
, pkg
->filename
, goto cleanup
);
444 STRDUP(newpkg
->name
, pkg
->name
, goto cleanup
);
445 STRDUP(newpkg
->version
, pkg
->version
, goto cleanup
);
446 STRDUP(newpkg
->desc
, pkg
->desc
, goto cleanup
);
447 STRDUP(newpkg
->url
, pkg
->url
, goto cleanup
);
448 newpkg
->builddate
= pkg
->builddate
;
449 newpkg
->installdate
= pkg
->installdate
;
450 STRDUP(newpkg
->packager
, pkg
->packager
, goto cleanup
);
451 STRDUP(newpkg
->md5sum
, pkg
->md5sum
, goto cleanup
);
452 STRDUP(newpkg
->arch
, pkg
->arch
, goto cleanup
);
453 newpkg
->size
= pkg
->size
;
454 newpkg
->isize
= pkg
->isize
;
455 newpkg
->scriptlet
= pkg
->scriptlet
;
456 newpkg
->reason
= pkg
->reason
;
458 newpkg
->licenses
= alpm_list_strdup(pkg
->licenses
);
459 newpkg
->replaces
= alpm_list_strdup(pkg
->replaces
);
460 newpkg
->groups
= alpm_list_strdup(pkg
->groups
);
461 newpkg
->files
= alpm_list_strdup(pkg
->files
);
462 for(i
= pkg
->backup
; i
; i
= alpm_list_next(i
)) {
463 newpkg
->backup
= alpm_list_add(newpkg
->backup
, _alpm_backup_dup(i
->data
));
465 for(i
= pkg
->depends
; i
; i
= alpm_list_next(i
)) {
466 newpkg
->depends
= alpm_list_add(newpkg
->depends
, _alpm_dep_dup(i
->data
));
468 newpkg
->optdepends
= alpm_list_strdup(pkg
->optdepends
);
469 newpkg
->conflicts
= alpm_list_strdup(pkg
->conflicts
);
470 newpkg
->provides
= alpm_list_strdup(pkg
->provides
);
471 for(i
= pkg
->deltas
; i
; i
= alpm_list_next(i
)) {
472 newpkg
->deltas
= alpm_list_add(newpkg
->deltas
, _alpm_delta_dup(i
->data
));
476 newpkg
->infolevel
= pkg
->infolevel
;
477 newpkg
->origin
= pkg
->origin
;
478 if(newpkg
->origin
== PKG_FROM_FILE
) {
479 newpkg
->origin_data
.file
= strdup(pkg
->origin_data
.file
);
481 newpkg
->origin_data
.db
= pkg
->origin_data
.db
;
483 newpkg
->ops
= pkg
->ops
;
484 newpkg
->handle
= pkg
->handle
;
489 _alpm_pkg_free(newpkg
);
493 void _alpm_pkg_free(pmpkg_t
*pkg
)
506 FREE(pkg
->base64_sig
);
508 FREELIST(pkg
->licenses
);
509 FREELIST(pkg
->replaces
);
510 FREELIST(pkg
->groups
);
511 FREELIST(pkg
->files
);
512 alpm_list_free_inner(pkg
->backup
, (alpm_list_fn_free
)_alpm_backup_free
);
513 alpm_list_free(pkg
->backup
);
514 alpm_list_free_inner(pkg
->depends
, (alpm_list_fn_free
)_alpm_dep_free
);
515 alpm_list_free(pkg
->depends
);
516 FREELIST(pkg
->optdepends
);
517 FREELIST(pkg
->conflicts
);
518 FREELIST(pkg
->provides
);
519 alpm_list_free_inner(pkg
->deltas
, (alpm_list_fn_free
)_alpm_delta_free
);
520 alpm_list_free(pkg
->deltas
);
521 alpm_list_free(pkg
->delta_path
);
522 alpm_list_free(pkg
->removes
);
524 if(pkg
->origin
== PKG_FROM_FILE
) {
525 FREE(pkg
->origin_data
.file
);
530 /* This function should be used when removing a target from upgrade/sync target list
531 * Case 1: If pkg is a loaded package file (PKG_FROM_FILE), it will be freed.
532 * Case 2: If pkg is a pkgcache entry (PKG_FROM_CACHE), it won't be freed,
533 * only the transaction specific fields of pkg will be freed.
535 void _alpm_pkg_free_trans(pmpkg_t
*pkg
)
541 if(pkg
->origin
== PKG_FROM_FILE
) {
546 alpm_list_free(pkg
->removes
);
550 /* Is spkg an upgrade for localpkg? */
551 int _alpm_pkg_compare_versions(pmpkg_t
*spkg
, pmpkg_t
*localpkg
)
553 return alpm_pkg_vercmp(alpm_pkg_get_version(spkg
),
554 alpm_pkg_get_version(localpkg
));
557 /* Helper function for comparing packages
559 int _alpm_pkg_cmp(const void *p1
, const void *p2
)
561 pmpkg_t
*pkg1
= (pmpkg_t
*)p1
;
562 pmpkg_t
*pkg2
= (pmpkg_t
*)p2
;
563 return strcoll(pkg1
->name
, pkg2
->name
);
566 /* Test for existence of a package in a alpm_list_t*
569 pmpkg_t
*_alpm_pkg_find(alpm_list_t
*haystack
, const char *needle
)
572 unsigned long needle_hash
;
574 if(needle
== NULL
|| haystack
== NULL
) {
578 needle_hash
= _alpm_hash_sdbm(needle
);
580 for(lp
= haystack
; lp
; lp
= lp
->next
) {
581 pmpkg_t
*info
= lp
->data
;
584 /* a zero hash will cause a fall-through just in case */
585 if(info
->name_hash
&& info
->name_hash
!= needle_hash
) {
589 /* finally: we had hash match, verify string match */
590 if(strcmp(info
->name
, needle
) == 0) {
598 /** Test if a package should be ignored.
600 * Checks if the package is ignored via IgnorePkg, or if the package is
601 * in a group ignored via IgnoreGrp.
603 * @param handle the context handle
604 * @param pkg the package to test
606 * @return 1 if the package should be ignored, 0 otherwise
608 int _alpm_pkg_should_ignore(alpm_handle_t
*handle
, pmpkg_t
*pkg
)
610 alpm_list_t
*groups
= NULL
;
612 /* first see if the package is ignored */
613 if(alpm_list_find_str(handle
->ignorepkg
, alpm_pkg_get_name(pkg
))) {
617 /* next see if the package is in a group that is ignored */
618 for(groups
= handle
->ignoregrp
; groups
; groups
= alpm_list_next(groups
)) {
619 char *grp
= (char *)alpm_list_getdata(groups
);
620 if(alpm_list_find_str(alpm_pkg_get_groups(pkg
), grp
)) {
628 /* vim: set ts=2 sw=2 noet: */