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
)
50 ASSERT(pkg
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
52 /* Only free packages loaded in user space */
53 if(pkg
->origin
== PKG_FROM_FILE
) {
60 /** Check the integrity (with md5) of a package from the sync cache. */
61 int SYMEXPORT
alpm_pkg_checkmd5sum(pmpkg_t
*pkg
)
68 ASSERT(pkg
!= NULL
, RET_ERR(PM_ERR_WRONG_ARGS
, -1));
69 /* We only inspect packages from sync repositories */
70 ASSERT(pkg
->origin
== PKG_FROM_SYNCDB
, RET_ERR(PM_ERR_PKG_INVALID
, -1));
72 fpath
= _alpm_filecache_find(alpm_pkg_get_filename(pkg
));
74 retval
= _alpm_test_md5sum(fpath
, alpm_pkg_get_md5sum(pkg
));
78 } else if(retval
== 1) {
79 pm_errno
= PM_ERR_PKG_INVALID
;
86 /* Default package accessor functions. These will get overridden by any
87 * backend logic that needs lazy access, such as the local database through
88 * a lazy-load cache. However, the defaults will work just fine for fully-
89 * populated package structures. */
90 static const char *_pkg_get_filename(pmpkg_t
*pkg
) { return pkg
->filename
; }
91 static const char *_pkg_get_desc(pmpkg_t
*pkg
) { return pkg
->desc
; }
92 static const char *_pkg_get_url(pmpkg_t
*pkg
) { return pkg
->url
; }
93 static time_t _pkg_get_builddate(pmpkg_t
*pkg
) { return pkg
->builddate
; }
94 static time_t _pkg_get_installdate(pmpkg_t
*pkg
) { return pkg
->installdate
; }
95 static const char *_pkg_get_packager(pmpkg_t
*pkg
) { return pkg
->packager
; }
96 static const char *_pkg_get_md5sum(pmpkg_t
*pkg
) { return pkg
->md5sum
; }
97 static const char *_pkg_get_arch(pmpkg_t
*pkg
) { return pkg
->arch
; }
98 static off_t
_pkg_get_size(pmpkg_t
*pkg
) { return pkg
->size
; }
99 static off_t
_pkg_get_isize(pmpkg_t
*pkg
) { return pkg
->isize
; }
100 static pmpkgreason_t
_pkg_get_reason(pmpkg_t
*pkg
) { return pkg
->reason
; }
101 static int _pkg_has_scriptlet(pmpkg_t
*pkg
) { return pkg
->scriptlet
; }
103 static alpm_list_t
*_pkg_get_licenses(pmpkg_t
*pkg
) { return pkg
->licenses
; }
104 static alpm_list_t
*_pkg_get_groups(pmpkg_t
*pkg
) { return pkg
->groups
; }
105 static alpm_list_t
*_pkg_get_depends(pmpkg_t
*pkg
) { return pkg
->depends
; }
106 static alpm_list_t
*_pkg_get_optdepends(pmpkg_t
*pkg
) { return pkg
->optdepends
; }
107 static alpm_list_t
*_pkg_get_conflicts(pmpkg_t
*pkg
) { return pkg
->conflicts
; }
108 static alpm_list_t
*_pkg_get_provides(pmpkg_t
*pkg
) { return pkg
->provides
; }
109 static alpm_list_t
*_pkg_get_replaces(pmpkg_t
*pkg
) { return pkg
->replaces
; }
110 static alpm_list_t
*_pkg_get_deltas(pmpkg_t
*pkg
) { return pkg
->deltas
; }
111 static alpm_list_t
*_pkg_get_files(pmpkg_t
*pkg
) { return pkg
->files
; }
112 static alpm_list_t
*_pkg_get_backup(pmpkg_t
*pkg
) { return pkg
->backup
; }
114 static void *_pkg_changelog_open(pmpkg_t UNUSED
*pkg
)
119 static size_t _pkg_changelog_read(void UNUSED
*ptr
, size_t UNUSED size
,
120 const pmpkg_t UNUSED
*pkg
, const UNUSED
void *fp
)
125 static int _pkg_changelog_close(const pmpkg_t UNUSED
*pkg
,
131 /** The standard package operations struct. Get fields directly from the
132 * struct itself with no abstraction layer or any type of lazy loading.
134 struct pkg_operations default_pkg_ops
= {
135 .get_filename
= _pkg_get_filename
,
136 .get_desc
= _pkg_get_desc
,
137 .get_url
= _pkg_get_url
,
138 .get_builddate
= _pkg_get_builddate
,
139 .get_installdate
= _pkg_get_installdate
,
140 .get_packager
= _pkg_get_packager
,
141 .get_md5sum
= _pkg_get_md5sum
,
142 .get_arch
= _pkg_get_arch
,
143 .get_size
= _pkg_get_size
,
144 .get_isize
= _pkg_get_isize
,
145 .get_reason
= _pkg_get_reason
,
146 .has_scriptlet
= _pkg_has_scriptlet
,
148 .get_licenses
= _pkg_get_licenses
,
149 .get_groups
= _pkg_get_groups
,
150 .get_depends
= _pkg_get_depends
,
151 .get_optdepends
= _pkg_get_optdepends
,
152 .get_conflicts
= _pkg_get_conflicts
,
153 .get_provides
= _pkg_get_provides
,
154 .get_replaces
= _pkg_get_replaces
,
155 .get_deltas
= _pkg_get_deltas
,
156 .get_files
= _pkg_get_files
,
157 .get_backup
= _pkg_get_backup
,
159 .changelog_open
= _pkg_changelog_open
,
160 .changelog_read
= _pkg_changelog_read
,
161 .changelog_close
= _pkg_changelog_close
,
164 /* Public functions for getting package information. These functions
165 * delegate the hard work to the function callbacks attached to each
166 * package, which depend on where the package was loaded from. */
167 const char SYMEXPORT
*alpm_pkg_get_filename(pmpkg_t
*pkg
)
169 return pkg
->ops
->get_filename(pkg
);
172 const char SYMEXPORT
*alpm_pkg_get_name(pmpkg_t
*pkg
)
177 const char SYMEXPORT
*alpm_pkg_get_version(pmpkg_t
*pkg
)
182 const char SYMEXPORT
*alpm_pkg_get_desc(pmpkg_t
*pkg
)
184 return pkg
->ops
->get_desc(pkg
);
187 const char SYMEXPORT
*alpm_pkg_get_url(pmpkg_t
*pkg
)
189 return pkg
->ops
->get_url(pkg
);
192 time_t SYMEXPORT
alpm_pkg_get_builddate(pmpkg_t
*pkg
)
194 return pkg
->ops
->get_builddate(pkg
);
197 time_t SYMEXPORT
alpm_pkg_get_installdate(pmpkg_t
*pkg
)
199 return pkg
->ops
->get_installdate(pkg
);
202 const char SYMEXPORT
*alpm_pkg_get_packager(pmpkg_t
*pkg
)
204 return pkg
->ops
->get_packager(pkg
);
207 const char SYMEXPORT
*alpm_pkg_get_md5sum(pmpkg_t
*pkg
)
209 return pkg
->ops
->get_md5sum(pkg
);
212 const char SYMEXPORT
*alpm_pkg_get_arch(pmpkg_t
*pkg
)
214 return pkg
->ops
->get_arch(pkg
);
217 off_t SYMEXPORT
alpm_pkg_get_size(pmpkg_t
*pkg
)
219 return pkg
->ops
->get_size(pkg
);
222 off_t SYMEXPORT
alpm_pkg_get_isize(pmpkg_t
*pkg
)
224 return pkg
->ops
->get_isize(pkg
);
227 pmpkgreason_t SYMEXPORT
alpm_pkg_get_reason(pmpkg_t
*pkg
)
229 return pkg
->ops
->get_reason(pkg
);
232 alpm_list_t SYMEXPORT
*alpm_pkg_get_licenses(pmpkg_t
*pkg
)
234 return pkg
->ops
->get_licenses(pkg
);
237 alpm_list_t SYMEXPORT
*alpm_pkg_get_groups(pmpkg_t
*pkg
)
239 return pkg
->ops
->get_groups(pkg
);
242 alpm_list_t SYMEXPORT
*alpm_pkg_get_depends(pmpkg_t
*pkg
)
244 return pkg
->ops
->get_depends(pkg
);
247 alpm_list_t SYMEXPORT
*alpm_pkg_get_optdepends(pmpkg_t
*pkg
)
249 return pkg
->ops
->get_optdepends(pkg
);
252 alpm_list_t SYMEXPORT
*alpm_pkg_get_conflicts(pmpkg_t
*pkg
)
254 return pkg
->ops
->get_conflicts(pkg
);
257 alpm_list_t SYMEXPORT
*alpm_pkg_get_provides(pmpkg_t
*pkg
)
259 return pkg
->ops
->get_provides(pkg
);
262 alpm_list_t SYMEXPORT
*alpm_pkg_get_replaces(pmpkg_t
*pkg
)
264 return pkg
->ops
->get_replaces(pkg
);
267 alpm_list_t SYMEXPORT
*alpm_pkg_get_deltas(pmpkg_t
*pkg
)
269 return pkg
->ops
->get_deltas(pkg
);
272 alpm_list_t SYMEXPORT
*alpm_pkg_get_files(pmpkg_t
*pkg
)
274 return pkg
->ops
->get_files(pkg
);
277 alpm_list_t SYMEXPORT
*alpm_pkg_get_backup(pmpkg_t
*pkg
)
279 return pkg
->ops
->get_backup(pkg
);
282 pmdb_t SYMEXPORT
*alpm_pkg_get_db(pmpkg_t
*pkg
)
285 ASSERT(pkg
!= NULL
, return NULL
);
286 ASSERT(pkg
->origin
!= PKG_FROM_FILE
, return NULL
);
288 return pkg
->origin_data
.db
;
291 /** Open a package changelog for reading. */
292 void SYMEXPORT
*alpm_pkg_changelog_open(pmpkg_t
*pkg
)
294 return pkg
->ops
->changelog_open(pkg
);
297 /** Read data from an open changelog 'file stream'. */
298 size_t SYMEXPORT
alpm_pkg_changelog_read(void *ptr
, size_t size
,
299 const pmpkg_t
*pkg
, const void *fp
)
301 return pkg
->ops
->changelog_read(ptr
, size
, pkg
, fp
);
305 int SYMEXPORT alpm_pkg_changelog_feof(const pmpkg_t *pkg, void *fp)
307 return pkg->ops->changelog_feof(pkg, fp);
311 /** Close a package changelog for reading. */
312 int SYMEXPORT
alpm_pkg_changelog_close(const pmpkg_t
*pkg
, void *fp
)
314 return pkg
->ops
->changelog_close(pkg
, fp
);
317 int SYMEXPORT
alpm_pkg_has_scriptlet(pmpkg_t
*pkg
)
319 return pkg
->ops
->has_scriptlet(pkg
);
322 static void find_requiredby(pmpkg_t
*pkg
, pmdb_t
*db
, alpm_list_t
**reqs
)
324 const alpm_list_t
*i
;
325 for(i
= _alpm_db_get_pkgcache(db
); i
; i
= i
->next
) {
326 pmpkg_t
*cachepkg
= i
->data
;
328 for(i
= alpm_pkg_get_depends(cachepkg
); i
; i
= i
->next
) {
329 if(_alpm_depcmp(pkg
, i
->data
)) {
330 const char *cachepkgname
= cachepkg
->name
;
331 if(alpm_list_find_str(*reqs
, cachepkgname
) == NULL
) {
332 *reqs
= alpm_list_add(*reqs
, strdup(cachepkgname
));
339 /** Compute the packages requiring a given package. */
340 alpm_list_t SYMEXPORT
*alpm_pkg_compute_requiredby(pmpkg_t
*pkg
)
342 const alpm_list_t
*i
;
343 alpm_list_t
*reqs
= NULL
;
346 if(pkg
->origin
== PKG_FROM_FILE
) {
347 /* The sane option; search locally for things that require this. */
348 db
= alpm_option_get_localdb();
349 find_requiredby(pkg
, db
, &reqs
);
351 /* We have a DB package. if it is a local package, then we should
352 * only search the local DB; else search all known sync databases. */
353 db
= pkg
->origin_data
.db
;
355 find_requiredby(pkg
, db
, &reqs
);
357 for(i
= handle
->dbs_sync
; i
; i
= i
->next
) {
359 find_requiredby(pkg
, db
, &reqs
);
361 reqs
= alpm_list_msort(reqs
, alpm_list_count(reqs
), _alpm_str_cmp
);
369 pmpkg_t
*_alpm_pkg_new(void)
375 CALLOC(pkg
, 1, sizeof(pmpkg_t
), RET_ERR(PM_ERR_MEMORY
, NULL
));
380 pmpkg_t
*_alpm_pkg_dup(pmpkg_t
*pkg
)
387 CALLOC(newpkg
, 1, sizeof(pmpkg_t
), RET_ERR(PM_ERR_MEMORY
, NULL
));
389 newpkg
->name_hash
= pkg
->name_hash
;
390 STRDUP(newpkg
->filename
, pkg
->filename
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
391 STRDUP(newpkg
->name
, pkg
->name
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
392 STRDUP(newpkg
->version
, pkg
->version
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
393 STRDUP(newpkg
->desc
, pkg
->desc
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
394 STRDUP(newpkg
->url
, pkg
->url
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
395 newpkg
->builddate
= pkg
->builddate
;
396 newpkg
->installdate
= pkg
->installdate
;
397 STRDUP(newpkg
->packager
, pkg
->packager
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
398 STRDUP(newpkg
->md5sum
, pkg
->md5sum
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
399 STRDUP(newpkg
->arch
, pkg
->arch
, RET_ERR(PM_ERR_MEMORY
, newpkg
));
400 newpkg
->size
= pkg
->size
;
401 newpkg
->isize
= pkg
->isize
;
402 newpkg
->scriptlet
= pkg
->scriptlet
;
403 newpkg
->reason
= pkg
->reason
;
405 newpkg
->licenses
= alpm_list_strdup(pkg
->licenses
);
406 newpkg
->replaces
= alpm_list_strdup(pkg
->replaces
);
407 newpkg
->groups
= alpm_list_strdup(pkg
->groups
);
408 newpkg
->files
= alpm_list_strdup(pkg
->files
);
409 newpkg
->backup
= alpm_list_strdup(pkg
->backup
);
410 for(i
= pkg
->depends
; i
; i
= alpm_list_next(i
)) {
411 newpkg
->depends
= alpm_list_add(newpkg
->depends
, _alpm_dep_dup(i
->data
));
413 newpkg
->optdepends
= alpm_list_strdup(pkg
->optdepends
);
414 newpkg
->conflicts
= alpm_list_strdup(pkg
->conflicts
);
415 newpkg
->provides
= alpm_list_strdup(pkg
->provides
);
416 newpkg
->deltas
= alpm_list_copy_data(pkg
->deltas
, sizeof(pmdelta_t
));
419 newpkg
->origin
= pkg
->origin
;
420 newpkg
->ops
= pkg
->ops
;
421 if(newpkg
->origin
== PKG_FROM_FILE
) {
422 newpkg
->origin_data
.file
= strdup(pkg
->origin_data
.file
);
424 newpkg
->origin_data
.db
= pkg
->origin_data
.db
;
426 newpkg
->infolevel
= pkg
->infolevel
;
431 void _alpm_pkg_free(pmpkg_t
*pkg
)
446 FREE(pkg
->base64_sig
);
448 FREELIST(pkg
->licenses
);
449 FREELIST(pkg
->replaces
);
450 FREELIST(pkg
->groups
);
451 FREELIST(pkg
->files
);
452 FREELIST(pkg
->backup
);
453 alpm_list_free_inner(pkg
->depends
, (alpm_list_fn_free
)_alpm_dep_free
);
454 alpm_list_free(pkg
->depends
);
455 FREELIST(pkg
->optdepends
);
456 FREELIST(pkg
->conflicts
);
457 FREELIST(pkg
->provides
);
458 alpm_list_free_inner(pkg
->deltas
, (alpm_list_fn_free
)_alpm_delta_free
);
459 alpm_list_free(pkg
->deltas
);
460 alpm_list_free(pkg
->delta_path
);
461 alpm_list_free(pkg
->removes
);
463 if(pkg
->origin
== PKG_FROM_FILE
) {
464 FREE(pkg
->origin_data
.file
);
469 /* This function should be used when removing a target from upgrade/sync target list
470 * Case 1: If pkg is a loaded package file (PKG_FROM_FILE), it will be freed.
471 * Case 2: If pkg is a pkgcache entry (PKG_FROM_CACHE), it won't be freed,
472 * only the transaction specific fields of pkg will be freed.
474 void _alpm_pkg_free_trans(pmpkg_t
*pkg
)
482 if(pkg
->origin
== PKG_FROM_FILE
) {
487 alpm_list_free(pkg
->removes
);
491 /* Is spkg an upgrade for localpkg? */
492 int _alpm_pkg_compare_versions(pmpkg_t
*spkg
, pmpkg_t
*localpkg
)
496 return alpm_pkg_vercmp(alpm_pkg_get_version(spkg
),
497 alpm_pkg_get_version(localpkg
));
500 /* Helper function for comparing packages
502 int _alpm_pkg_cmp(const void *p1
, const void *p2
)
504 pmpkg_t
*pkg1
= (pmpkg_t
*)p1
;
505 pmpkg_t
*pkg2
= (pmpkg_t
*)p2
;
506 return strcoll(pkg1
->name
, pkg2
->name
);
509 /* Test for existence of a package in a alpm_list_t*
512 pmpkg_t
*_alpm_pkg_find(alpm_list_t
*haystack
, const char *needle
)
515 unsigned long needle_hash
;
519 if(needle
== NULL
|| haystack
== NULL
) {
523 needle_hash
= _alpm_hash_sdbm(needle
);
525 for(lp
= haystack
; lp
; lp
= lp
->next
) {
526 pmpkg_t
*info
= lp
->data
;
529 /* a zero hash will cause a fall-through just in case */
530 if(info
->name_hash
&& info
->name_hash
!= needle_hash
) {
534 /* finally: we had hash match, verify string match */
535 if(strcmp(info
->name
, needle
) == 0) {
543 /** Test if a package should be ignored.
545 * Checks if the package is ignored via IgnorePkg, or if the package is
546 * in a group ignored via IgnoreGrp.
548 * @param pkg the package to test
550 * @return 1 if the package should be ignored, 0 otherwise
552 int _alpm_pkg_should_ignore(pmpkg_t
*pkg
)
554 alpm_list_t
*groups
= NULL
;
556 /* first see if the package is ignored */
557 if(alpm_list_find_str(handle
->ignorepkg
, alpm_pkg_get_name(pkg
))) {
561 /* next see if the package is in a group that is ignored */
562 for(groups
= handle
->ignoregrp
; groups
; groups
= alpm_list_next(groups
)) {
563 char *grp
= (char *)alpm_list_getdata(groups
);
564 if(alpm_list_find_str(alpm_pkg_get_groups(pkg
), grp
)) {
572 /* vim: set ts=2 sw=2 noet: */